~~~~ switch 203 ~~~~
diff --git a/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java b/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java.193
similarity index 100%
rename from build-common/src/com/intellij/util/io/JpsPersistentHashMap.java
rename to build-common/src/com/intellij/util/io/JpsPersistentHashMap.java.193
diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
index 7cfcb00..614426e 100644
--- a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
+++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
@@ -18,7 +18,7 @@
import com.intellij.util.io.DataExternalizer
import com.intellij.util.io.KeyDescriptor
-import com.intellij.util.io.JpsPersistentHashMap
+import com.intellij.util.io.PersistentHashMap
import java.io.File
@@ -28,10 +28,10 @@
private val valueExternalizer: DataExternalizer<V>
) : LazyStorage<K, V> {
@Volatile
- private var storage: JpsPersistentHashMap<K, V>? = null
+ private var storage: PersistentHashMap<K, V>? = null
@Synchronized
- private fun getStorageIfExists(): JpsPersistentHashMap<K, V>? {
+ private fun getStorageIfExists(): PersistentHashMap<K, V>? {
if (storage != null) return storage
if (storageFile.exists()) {
@@ -43,7 +43,7 @@
}
@Synchronized
- private fun getStorageOrCreateNew(): JpsPersistentHashMap<K, V> {
+ private fun getStorageOrCreateNew(): PersistentHashMap<K, V> {
if (storage == null) {
storage = createMap()
}
@@ -69,7 +69,7 @@
}
override fun append(key: K, value: V) {
- getStorageOrCreateNew().appendDataWithoutCache(key, value)
+ getStorageOrCreateNew().appendData(key) { dataOutput -> valueExternalizer.save(dataOutput, value) }
}
@Synchronized
@@ -79,7 +79,7 @@
} catch (ignored: Throwable) {
}
- JpsPersistentHashMap.deleteFilesStartingWith(storageFile)
+ PersistentHashMap.deleteFilesStartingWith(storageFile)
storage = null
}
@@ -101,6 +101,6 @@
storage?.close()
}
- private fun createMap(): JpsPersistentHashMap<K, V> =
- JpsPersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
+ private fun createMap(): PersistentHashMap<K, V> =
+ PersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
}
diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193 b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193
new file mode 100644
index 0000000..7cfcb00
--- /dev/null
+++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193
@@ -0,0 +1,106 @@
+/*
+ * 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.incremental.storage
+
+import com.intellij.util.io.DataExternalizer
+import com.intellij.util.io.KeyDescriptor
+import com.intellij.util.io.JpsPersistentHashMap
+import java.io.File
+
+
+class NonCachingLazyStorage<K, V>(
+ private val storageFile: File,
+ private val keyDescriptor: KeyDescriptor<K>,
+ private val valueExternalizer: DataExternalizer<V>
+) : LazyStorage<K, V> {
+ @Volatile
+ private var storage: JpsPersistentHashMap<K, V>? = null
+
+ @Synchronized
+ private fun getStorageIfExists(): JpsPersistentHashMap<K, V>? {
+ if (storage != null) return storage
+
+ if (storageFile.exists()) {
+ storage = createMap()
+ return storage
+ }
+
+ return null
+ }
+
+ @Synchronized
+ private fun getStorageOrCreateNew(): JpsPersistentHashMap<K, V> {
+ if (storage == null) {
+ storage = createMap()
+ }
+
+ return storage!!
+ }
+
+ override val keys: Collection<K>
+ get() = getStorageIfExists()?.allKeysWithExistingMapping ?: listOf()
+
+ override operator fun contains(key: K): Boolean =
+ getStorageIfExists()?.containsMapping(key) ?: false
+
+ override operator fun get(key: K): V? =
+ getStorageIfExists()?.get(key)
+
+ override operator fun set(key: K, value: V) {
+ getStorageOrCreateNew().put(key, value)
+ }
+
+ override fun remove(key: K) {
+ getStorageIfExists()?.remove(key)
+ }
+
+ override fun append(key: K, value: V) {
+ getStorageOrCreateNew().appendDataWithoutCache(key, value)
+ }
+
+ @Synchronized
+ override fun clean() {
+ try {
+ storage?.close()
+ } catch (ignored: Throwable) {
+ }
+
+ JpsPersistentHashMap.deleteFilesStartingWith(storageFile)
+ storage = null
+ }
+
+ @Synchronized
+ override fun flush(memoryCachesOnly: Boolean) {
+ val existingStorage = storage ?: return
+
+ if (memoryCachesOnly) {
+ if (existingStorage.isDirty) {
+ existingStorage.dropMemoryCaches()
+ }
+ } else {
+ existingStorage.force()
+ }
+ }
+
+ @Synchronized
+ override fun close() {
+ storage?.close()
+ }
+
+ private fun createMap(): JpsPersistentHashMap<K, V> =
+ JpsPersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
+}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt
index 9e63629..810a5a7 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt
@@ -8,4 +8,4 @@
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
-typealias SourceFrames = Array<Frame<SourceValue>?>
\ No newline at end of file
+typealias SourceFrames = Array<Frame<SourceValue>>
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt.193 b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt.193
new file mode 100644
index 0000000..9e63629
--- /dev/null
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SourceFrames.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.codegen.coroutines
+
+import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
+import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
+
+typealias SourceFrames = Array<Frame<SourceValue>?>
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt
index 774af10..06673d2 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt
@@ -8,4 +8,4 @@
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
-typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>
\ No newline at end of file
+typealias TypeAnnotatedFrames = Array<Frame<BasicValue>>
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt.193 b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt.193
new file mode 100644
index 0000000..774af10
--- /dev/null
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TypeAnnotatedFrames.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.codegen.optimization.common
+
+import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
+import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
+
+typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt
index ebab87a..ee6e176 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt
@@ -5,4 +5,4 @@
package org.jetbrains.kotlin.codegen.state
-typealias JvmMethodExceptionTypes = Array<out String>?
\ No newline at end of file
+typealias JvmMethodExceptionTypes = Array<out String?>?
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt.193 b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt.193
new file mode 100644
index 0000000..ebab87a
--- /dev/null
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JvmMethodExceptionTypes.kt.193
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.codegen.state
+
+typealias JvmMethodExceptionTypes = Array<out String>?
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt
index 2d82644..f560fc9 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt
@@ -31,6 +31,6 @@
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render,
- MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
+ MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
)
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt.193
new file mode 100644
index 0000000..2d82644
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/DefaultDiagnosticReporter.kt.193
@@ -0,0 +1,36 @@
+/*
+ * 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.cli.common.messages
+
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
+
+/**
+ * This class behaviour is the same as [MessageCollector.report] in [AnalyzerWithCompilerReport.reportDiagnostic].
+ */
+class DefaultDiagnosticReporter(override val messageCollector: MessageCollector) : MessageCollectorBasedReporter
+
+interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
+ val messageCollector: MessageCollector
+
+ override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
+ AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
+ render,
+ MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
+ )
+}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java
index 03f291e..2ac1c17 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java
@@ -17,8 +17,6 @@
package org.jetbrains.kotlin.cli.common.messages;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.impl.jar.CoreJarVirtualFile;
-import com.intellij.openapi.vfs.local.CoreLocalVirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
@@ -32,31 +30,25 @@
private MessageUtil() {}
@Nullable
- public static CompilerMessageSourceLocation psiElementToMessageLocation(@Nullable PsiElement element) {
+ public static CompilerMessageLocation psiElementToMessageLocation(@Nullable PsiElement element) {
if (element == null) return null;
PsiFile file = element.getContainingFile();
- return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnRangeInPsiFile(file, element.getTextRange()));
+ return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnInPsiFile(file, element.getTextRange()));
}
@Nullable
- public static CompilerMessageSourceLocation psiFileToMessageLocation(
+ public static CompilerMessageLocation psiFileToMessageLocation(
@NotNull PsiFile file,
@Nullable String defaultValue,
- @NotNull PsiDiagnosticUtils.LineAndColumnRange range
+ @NotNull PsiDiagnosticUtils.LineAndColumn lineAndColumn
) {
VirtualFile virtualFile = file.getVirtualFile();
String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
- PsiDiagnosticUtils.LineAndColumn start = range.getStart();
- PsiDiagnosticUtils.LineAndColumn end = range.getEnd();
- return CompilerMessageLocationWithRange.create(path, start.getLine(), start.getColumn(), end.getLine(), end.getColumn(), start.getLineContent());
+ return CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn(), lineAndColumn.getLineContent());
}
@NotNull
public static String virtualFileToPath(@NotNull VirtualFile virtualFile) {
- // Convert path to platform-dependent format when virtualFile is local file.
- if (virtualFile instanceof CoreLocalVirtualFile || virtualFile instanceof CoreJarVirtualFile) {
- return toSystemDependentName(virtualFile.getPath());
- }
- return virtualFile.getPath();
+ return toSystemDependentName(virtualFile.getPath());
}
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java.193
new file mode 100644
index 0000000..03f291e
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageUtil.java.193
@@ -0,0 +1,62 @@
+/*
+ * 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.cli.common.messages;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.impl.jar.CoreJarVirtualFile;
+import com.intellij.openapi.vfs.local.CoreLocalVirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
+import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils;
+
+import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
+
+public class MessageUtil {
+ private MessageUtil() {}
+
+ @Nullable
+ public static CompilerMessageSourceLocation psiElementToMessageLocation(@Nullable PsiElement element) {
+ if (element == null) return null;
+ PsiFile file = element.getContainingFile();
+ return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnRangeInPsiFile(file, element.getTextRange()));
+ }
+
+ @Nullable
+ public static CompilerMessageSourceLocation psiFileToMessageLocation(
+ @NotNull PsiFile file,
+ @Nullable String defaultValue,
+ @NotNull PsiDiagnosticUtils.LineAndColumnRange range
+ ) {
+ VirtualFile virtualFile = file.getVirtualFile();
+ String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
+ PsiDiagnosticUtils.LineAndColumn start = range.getStart();
+ PsiDiagnosticUtils.LineAndColumn end = range.getEnd();
+ return CompilerMessageLocationWithRange.create(path, start.getLine(), start.getColumn(), end.getLine(), end.getColumn(), start.getLineContent());
+ }
+
+ @NotNull
+ public static String virtualFileToPath(@NotNull VirtualFile virtualFile) {
+ // Convert path to platform-dependent format when virtualFile is local file.
+ if (virtualFile instanceof CoreLocalVirtualFile || virtualFile instanceof CoreJarVirtualFile) {
+ return toSystemDependentName(virtualFile.getPath());
+ }
+ return virtualFile.getPath();
+ }
+}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
index f5a5525..26562e4 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
@@ -4,147 +4,52 @@
*/
package org.jetbrains.kotlin.cli.jvm.compiler;
+import com.intellij.DynamicBundle;
import com.intellij.codeInsight.ContainerProvider;
-import com.intellij.codeInsight.JavaContainerProvider;
-import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
-import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsBase;
-import com.intellij.codeInsight.folding.impl.JavaFoldingBuilderBase;
import com.intellij.codeInsight.runner.JavaMainMethodProvider;
-import com.intellij.core.CoreApplicationEnvironment;
-import com.intellij.core.CoreJavaDirectoryService;
-import com.intellij.core.CorePsiPackageImplementationHelper;
-import com.intellij.ide.highlighter.ArchiveFileType;
-import com.intellij.ide.highlighter.JavaClassFileType;
-import com.intellij.ide.highlighter.JavaFileType;
-import com.intellij.lang.LanguageASTFactory;
+import com.intellij.core.JavaCoreApplicationEnvironment;
import com.intellij.lang.MetaLanguage;
-import com.intellij.lang.folding.LanguageFolding;
-import com.intellij.lang.java.JavaLanguage;
-import com.intellij.lang.java.JavaParserDefinition;
-import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.extensions.ExtensionsArea;
-import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
-import com.intellij.openapi.fileTypes.PlainTextFileType;
-import com.intellij.openapi.fileTypes.PlainTextLanguage;
-import com.intellij.openapi.fileTypes.PlainTextParserDefinition;
-import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.vfs.VirtualFileSystem;
-import com.intellij.psi.*;
+import com.intellij.psi.FileContextProvider;
import com.intellij.psi.augment.PsiAugmentProvider;
-import com.intellij.psi.augment.TypeAnnotationModifier;
import com.intellij.psi.compiled.ClassFileDecompilers;
-import com.intellij.psi.impl.LanguageConstantExpressionEvaluator;
-import com.intellij.psi.impl.PsiExpressionEvaluator;
-import com.intellij.psi.impl.PsiSubstitutorFactoryImpl;
-import com.intellij.psi.impl.compiled.ClassFileStubBuilder;
-import com.intellij.psi.impl.file.PsiPackageImplementationHelper;
-import com.intellij.psi.impl.search.MethodSuperSearcher;
-import com.intellij.psi.impl.source.tree.JavaASTFactory;
-import com.intellij.psi.impl.source.tree.PlainTextASTFactory;
import com.intellij.psi.meta.MetaDataContributor;
-import com.intellij.psi.presentation.java.*;
-import com.intellij.psi.search.searches.SuperMethodsSearch;
-import com.intellij.psi.stubs.BinaryFileStubBuilders;
-import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
-/**
- * adapted from com.intellij.core.JavaCoreApplicationEnvironment
- * TODO: initiate removal original from com.intellij.core since it seems that there are no usages left
- */
-public class KotlinCoreApplicationEnvironment extends CoreApplicationEnvironment {
+public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
+ public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
+ registerExtensionPoints();
+ return environment;
+ }
- public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
- return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
- }
+ private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ super(parentDisposable, unitTestMode);
+ }
- private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
- super(parentDisposable, unitTestMode);
+ private static void registerExtensionPoints() {
+ registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
+ registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
- registerExtensionPoints();
+ registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
+ registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
+ registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
- registerExtensions();
- }
+ registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
+ registerApplicationExtensionPoint(ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
- private void registerExtensionPoints() {
- ExtensionsArea area = Extensions.getRootArea();
+ registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
+ IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
+ }
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
-
- CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
-
- CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage.class);
-
- IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(area);
- }
-
- private void registerExtensions() {
- registerFileType(JavaClassFileType.INSTANCE, "class");
- registerFileType(JavaFileType.INSTANCE, "java");
- registerFileType(ArchiveFileType.INSTANCE, "jar;zip");
- registerFileType(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess");
-
- addExplicitExtension(LanguageASTFactory.INSTANCE, PlainTextLanguage.INSTANCE, new PlainTextASTFactory());
- registerParserDefinition(new PlainTextParserDefinition());
-
- addExplicitExtension(FileTypeFileViewProviders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileViewProviderFactory());
- addExplicitExtension(BinaryFileStubBuilders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileStubBuilder());
-
- addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
- registerParserDefinition(new JavaParserDefinition());
- addExplicitExtension(LanguageConstantExpressionEvaluator.INSTANCE, JavaLanguage.INSTANCE, new PsiExpressionEvaluator());
-
- addExtension(ContainerProvider.EP_NAME, new JavaContainerProvider());
-
- myApplication.registerService(PsiPackageImplementationHelper.class, new CorePsiPackageImplementationHelper());
- myApplication.registerService(PsiSubstitutorFactory.class, new PsiSubstitutorFactoryImpl());
-
- myApplication.registerService(JavaDirectoryService.class, createJavaDirectoryService());
- myApplication.registerService(JavaVersionService.class, new JavaVersionService());
-
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiPackage.class, new PackagePresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiClass.class, new ClassPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiMethod.class, new MethodPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiField.class, new FieldPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiLocalVariable.class, new VariablePresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiParameter.class, new VariablePresentationProvider());
-
- registerApplicationService(JavaCodeFoldingSettings.class, new JavaCodeFoldingSettingsBase());
- addExplicitExtension(LanguageFolding.INSTANCE, JavaLanguage.INSTANCE, new JavaFoldingBuilderBase() {
- @Override
- protected boolean shouldShowExplicitLambdaType(@NotNull PsiAnonymousClass anonymousClass, @NotNull PsiNewExpression expression) {
- return false;
- }
-
- @Override
- protected boolean isBelowRightMargin(@NotNull PsiFile file, int lineLength) {
- return false;
- }
- });
-
- registerApplicationExtensionPoint(SuperMethodsSearch.EP_NAME, QueryExecutor.class);
- addExtension(SuperMethodsSearch.EP_NAME, new MethodSuperSearcher());
- }
-
- // overridden in upsource
- protected CoreJavaDirectoryService createJavaDirectoryService() {
- return new CoreJavaDirectoryService();
- }
-
- @Nullable
- @Override
- protected VirtualFileSystem createJrtFileSystem() {
- return new CoreJrtFileSystem();
- }
+ @Nullable
+ @Override
+ protected VirtualFileSystem createJrtFileSystem() {
+ return new CoreJrtFileSystem();
+ }
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193
new file mode 100644
index 0000000..f5a5525
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.cli.jvm.compiler;
+
+import com.intellij.codeInsight.ContainerProvider;
+import com.intellij.codeInsight.JavaContainerProvider;
+import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
+import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsBase;
+import com.intellij.codeInsight.folding.impl.JavaFoldingBuilderBase;
+import com.intellij.codeInsight.runner.JavaMainMethodProvider;
+import com.intellij.core.CoreApplicationEnvironment;
+import com.intellij.core.CoreJavaDirectoryService;
+import com.intellij.core.CorePsiPackageImplementationHelper;
+import com.intellij.ide.highlighter.ArchiveFileType;
+import com.intellij.ide.highlighter.JavaClassFileType;
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.lang.LanguageASTFactory;
+import com.intellij.lang.MetaLanguage;
+import com.intellij.lang.folding.LanguageFolding;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.lang.java.JavaParserDefinition;
+import com.intellij.navigation.ItemPresentationProviders;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.extensions.ExtensionsArea;
+import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.openapi.fileTypes.PlainTextParserDefinition;
+import com.intellij.openapi.projectRoots.JavaVersionService;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import com.intellij.psi.*;
+import com.intellij.psi.augment.PsiAugmentProvider;
+import com.intellij.psi.augment.TypeAnnotationModifier;
+import com.intellij.psi.compiled.ClassFileDecompilers;
+import com.intellij.psi.impl.LanguageConstantExpressionEvaluator;
+import com.intellij.psi.impl.PsiExpressionEvaluator;
+import com.intellij.psi.impl.PsiSubstitutorFactoryImpl;
+import com.intellij.psi.impl.compiled.ClassFileStubBuilder;
+import com.intellij.psi.impl.file.PsiPackageImplementationHelper;
+import com.intellij.psi.impl.search.MethodSuperSearcher;
+import com.intellij.psi.impl.source.tree.JavaASTFactory;
+import com.intellij.psi.impl.source.tree.PlainTextASTFactory;
+import com.intellij.psi.meta.MetaDataContributor;
+import com.intellij.psi.presentation.java.*;
+import com.intellij.psi.search.searches.SuperMethodsSearch;
+import com.intellij.psi.stubs.BinaryFileStubBuilders;
+import com.intellij.util.QueryExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
+
+/**
+ * adapted from com.intellij.core.JavaCoreApplicationEnvironment
+ * TODO: initiate removal original from com.intellij.core since it seems that there are no usages left
+ */
+public class KotlinCoreApplicationEnvironment extends CoreApplicationEnvironment {
+
+ public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
+ }
+
+ private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ super(parentDisposable, unitTestMode);
+
+ registerExtensionPoints();
+
+ registerExtensions();
+ }
+
+ private void registerExtensionPoints() {
+ ExtensionsArea area = Extensions.getRootArea();
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage.class);
+
+ IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(area);
+ }
+
+ private void registerExtensions() {
+ registerFileType(JavaClassFileType.INSTANCE, "class");
+ registerFileType(JavaFileType.INSTANCE, "java");
+ registerFileType(ArchiveFileType.INSTANCE, "jar;zip");
+ registerFileType(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess");
+
+ addExplicitExtension(LanguageASTFactory.INSTANCE, PlainTextLanguage.INSTANCE, new PlainTextASTFactory());
+ registerParserDefinition(new PlainTextParserDefinition());
+
+ addExplicitExtension(FileTypeFileViewProviders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileViewProviderFactory());
+ addExplicitExtension(BinaryFileStubBuilders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileStubBuilder());
+
+ addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
+ registerParserDefinition(new JavaParserDefinition());
+ addExplicitExtension(LanguageConstantExpressionEvaluator.INSTANCE, JavaLanguage.INSTANCE, new PsiExpressionEvaluator());
+
+ addExtension(ContainerProvider.EP_NAME, new JavaContainerProvider());
+
+ myApplication.registerService(PsiPackageImplementationHelper.class, new CorePsiPackageImplementationHelper());
+ myApplication.registerService(PsiSubstitutorFactory.class, new PsiSubstitutorFactoryImpl());
+
+ myApplication.registerService(JavaDirectoryService.class, createJavaDirectoryService());
+ myApplication.registerService(JavaVersionService.class, new JavaVersionService());
+
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiPackage.class, new PackagePresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiClass.class, new ClassPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiMethod.class, new MethodPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiField.class, new FieldPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiLocalVariable.class, new VariablePresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiParameter.class, new VariablePresentationProvider());
+
+ registerApplicationService(JavaCodeFoldingSettings.class, new JavaCodeFoldingSettingsBase());
+ addExplicitExtension(LanguageFolding.INSTANCE, JavaLanguage.INSTANCE, new JavaFoldingBuilderBase() {
+ @Override
+ protected boolean shouldShowExplicitLambdaType(@NotNull PsiAnonymousClass anonymousClass, @NotNull PsiNewExpression expression) {
+ return false;
+ }
+
+ @Override
+ protected boolean isBelowRightMargin(@NotNull PsiFile file, int lineLength) {
+ return false;
+ }
+ });
+
+ registerApplicationExtensionPoint(SuperMethodsSearch.EP_NAME, QueryExecutor.class);
+ addExtension(SuperMethodsSearch.EP_NAME, new MethodSuperSearcher());
+ }
+
+ // overridden in upsource
+ protected CoreJavaDirectoryService createJavaDirectoryService() {
+ return new CoreJavaDirectoryService();
+ }
+
+ @Nullable
+ @Override
+ protected VirtualFileSystem createJrtFileSystem() {
+ return new CoreJrtFileSystem();
+ }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt
index 746e54d..c352086 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt
@@ -22,6 +22,7 @@
class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
override fun chooseAnnotationsPlace(element: PsiElement): AnnotationPlace = AnnotationPlace.NOWHERE
+ override fun chooseAnnotationsPlaceNoUi(element: PsiElement): AnnotationPlace = AnnotationPlace.NOWHERE
override fun isExternalAnnotationWritable(listOwner: PsiModifierListOwner, annotationFQN: String): Boolean = false
override fun isExternalAnnotation(annotation: PsiAnnotation): Boolean = false
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt.193
new file mode 100644
index 0000000..746e54d
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/MockExternalAnnotationsManager.kt.193
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+import com.intellij.codeInsight.ExternalAnnotationsManager
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.psi.*
+
+class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
+ override fun chooseAnnotationsPlace(element: PsiElement): AnnotationPlace = AnnotationPlace.NOWHERE
+
+ override fun isExternalAnnotationWritable(listOwner: PsiModifierListOwner, annotationFQN: String): Boolean = false
+ override fun isExternalAnnotation(annotation: PsiAnnotation): Boolean = false
+
+ override fun findExternalAnnotationsFiles(listOwner: PsiModifierListOwner): List<PsiFile>? = null
+ override fun findExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null
+ override fun findExternalAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation>? = null
+
+ override fun annotateExternally(
+ listOwner: PsiModifierListOwner,
+ annotationFQName: String,
+ fromFile: PsiFile,
+ value: Array<out PsiNameValuePair>?
+ ) {
+ throw UnsupportedOperationException("not implemented")
+ }
+
+ override fun deannotate(listOwner: PsiModifierListOwner, annotationFQN: String): Boolean {
+ throw UnsupportedOperationException("not implemented")
+ }
+
+ override fun editExternalAnnotation(
+ listOwner: PsiModifierListOwner,
+ annotationFQN: String,
+ value: Array<out PsiNameValuePair>?
+ ): Boolean {
+ throw UnsupportedOperationException("not implemented")
+ }
+
+ override fun hasAnnotationRootsForFile(file: VirtualFile): Boolean = false
+
+ override fun findDefaultConstructorExternalAnnotations(aClass: PsiClass, annotationFQN: String): List<PsiAnnotation> = emptyList()
+
+ override fun findDefaultConstructorExternalAnnotations(aClass: PsiClass): List<PsiAnnotation> = emptyList()
+
+ override fun findExternalAnnotations(listOwner: PsiModifierListOwner, annotationFQN: String): List<PsiAnnotation> = emptyList()
+}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
index e731677..1a12369 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
@@ -6,4 +6,10 @@
package org.jetbrains.kotlin.cli.jvm.compiler
fun setupIdeaStandaloneExecution() {
+ System.getProperties().setProperty("idea.plugins.compatible.build", "201.6668.13")
+ System.getProperties().setProperty("project.structure.add.tools.jar.to.new.jdk", "false")
+ System.getProperties().setProperty("psi.track.invalidation", "true")
+ System.getProperties().setProperty("psi.incremental.reparse.depth.limit", "1000")
+ System.getProperties().setProperty("ide.hide.excluded.files", "false")
+ System.getProperties().setProperty("ast.loading.filter", "false")
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193
new file mode 100644
index 0000000..e731677
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+fun setupIdeaStandaloneExecution() {
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
index 8327a2b..92159db 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
@@ -8,9 +8,11 @@
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.openapi.extensions.ExtensionsArea
import java.io.File
+import java.nio.file.FileSystems
// FIX ME WHEN BUNCH 193 REMOVED
fun registerExtensionPointAndExtensionsEx(pluginFile: File, fileName: String, area: ExtensionsArea) {
+ val pluginRoot = FileSystems.getDefault().getPath(pluginFile.path)
@Suppress("MissingRecentApi")
- CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginFile, fileName, area)
+ CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginRoot, fileName, area)
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193
new file mode 100644
index 0000000..8327a2b
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.openapi.extensions.ExtensionsArea
+import java.io.File
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun registerExtensionPointAndExtensionsEx(pluginFile: File, fileName: String, area: ExtensionsArea) {
+ @Suppress("MissingRecentApi")
+ CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginFile, fileName, area)
+}
\ No newline at end of file
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java
index 2e42e3a..912863a 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java
@@ -140,7 +140,6 @@
// That's for reparse routines
final PomModelImpl pomModel = new PomModelImpl(myProject);
myProject.registerService(PomModel.class, pomModel);
- new TreeAspect(pomModel);
}
public void configureFromParserDefinition(ParserDefinition definition, String extension) {
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java.193 b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java.193
new file mode 100644
index 0000000..2e42e3a
--- /dev/null
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtParsingTestCase.java.193
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2000-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.test.testFramework;
+
+import com.intellij.core.CoreASTFactory;
+import com.intellij.ide.util.AppPropertiesComponentImpl;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.lang.*;
+import com.intellij.lang.impl.PsiBuilderFactoryImpl;
+import com.intellij.mock.*;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
+import com.intellij.openapi.options.SchemeManagerFactory;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.impl.CoreProgressManager;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.pom.PomModel;
+import com.intellij.pom.core.impl.PomModelImpl;
+import com.intellij.pom.tree.TreeAspect;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.*;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.testFramework.MockSchemeManagerFactory;
+import com.intellij.testFramework.TestDataFile;
+import com.intellij.util.CachedValuesManagerImpl;
+import com.intellij.util.Function;
+import junit.framework.TestCase;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.idea.KotlinFileType;
+import org.picocontainer.ComponentAdapter;
+import org.picocontainer.MutablePicoContainer;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+@SuppressWarnings("ALL")
+public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
+ public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
+ protected String myFilePrefix = "";
+ protected String myFileExt;
+ protected final String myFullDataPath;
+ protected PsiFile myFile;
+ private MockPsiManager myPsiManager;
+ private PsiFileFactoryImpl myFileFactory;
+ protected Language myLanguage;
+ private final ParserDefinition[] myDefinitions;
+ private final boolean myLowercaseFirstLetter;
+
+ protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, @NotNull ParserDefinition... definitions) {
+ this(dataPath, fileExt, false, definitions);
+ }
+
+ protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, boolean lowercaseFirstLetter, @NotNull ParserDefinition... definitions) {
+ myDefinitions = definitions;
+ myFullDataPath = getTestDataPath() + "/" + dataPath;
+ myFileExt = fileExt;
+ myLowercaseFirstLetter = lowercaseFirstLetter;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ initApplication();
+ ComponentAdapter component = getApplication().getPicoContainer().getComponentAdapter(ProgressManager.class.getName());
+
+ Extensions.registerAreaClass("IDEA_PROJECT", null);
+ myProject = new MockProjectEx(getTestRootDisposable());
+ myPsiManager = new MockPsiManager(myProject);
+ myFileFactory = new PsiFileFactoryImpl(myPsiManager);
+ MutablePicoContainer appContainer = getApplication().getPicoContainer();
+ final MockEditorFactory editorFactory = new MockEditorFactory();
+ MockFileTypeManager mockFileTypeManager = new MockFileTypeManager(KotlinFileType.INSTANCE);
+ MockFileDocumentManagerImpl mockFileDocumentManager = new MockFileDocumentManagerImpl(new Function<CharSequence, Document>() {
+ @Override
+ public Document fun(CharSequence charSequence) {
+ return editorFactory.createDocument(charSequence);
+ }
+ }, HARD_REF_TO_DOCUMENT_KEY);
+
+ registerApplicationService(PropertiesComponent.class, new AppPropertiesComponentImpl());
+ registerApplicationService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
+ registerApplicationService(DefaultASTFactory.class, new CoreASTFactory());
+ registerApplicationService(SchemeManagerFactory.class, new MockSchemeManagerFactory());
+ registerApplicationService(FileTypeManager.class, mockFileTypeManager);
+ registerApplicationService(FileDocumentManager.class, mockFileDocumentManager);
+
+ registerApplicationService(ProgressManager.class, new CoreProgressManager());
+
+ registerComponentInstance(appContainer, FileTypeRegistry.class, mockFileTypeManager);
+ registerComponentInstance(appContainer, FileTypeManager.class, mockFileTypeManager);
+ registerComponentInstance(appContainer, EditorFactory.class, editorFactory);
+ registerComponentInstance(appContainer, FileDocumentManager.class, mockFileDocumentManager);
+ registerComponentInstance(appContainer, PsiDocumentManager.class, new MockPsiDocumentManager());
+
+
+ myProject.registerService(CachedValuesManager.class, new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(myPsiManager)));
+ myProject.registerService(PsiManager.class, myPsiManager);
+
+ this.registerExtensionPoint(FileTypeFactory.FILE_TYPE_FACTORY_EP, FileTypeFactory.class);
+ registerExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
+
+ for (ParserDefinition definition : myDefinitions) {
+ addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition);
+ }
+ if (myDefinitions.length > 0) {
+ configureFromParserDefinition(myDefinitions[0], myFileExt);
+ }
+
+ // That's for reparse routines
+ final PomModelImpl pomModel = new PomModelImpl(myProject);
+ myProject.registerService(PomModel.class, pomModel);
+ new TreeAspect(pomModel);
+ }
+
+ public void configureFromParserDefinition(ParserDefinition definition, String extension) {
+ myLanguage = definition.getFileNodeType().getLanguage();
+ myFileExt = extension;
+ addExplicitExtension(LanguageParserDefinitions.INSTANCE, this.myLanguage, definition);
+ registerComponentInstance(
+ getApplication().getPicoContainer(), FileTypeManager.class,
+ new MockFileTypeManager(new MockLanguageFileType(myLanguage, myFileExt)));
+ }
+
+ protected <T> void addExplicitExtension(final LanguageExtension<T> instance, final Language language, final T object) {
+ instance.addExplicitExtension(language, object);
+ Disposer.register(myProject, new Disposable() {
+ @Override
+ public void dispose() {
+ instance.removeExplicitExtension(language, object);
+ }
+ });
+ }
+
+ @Override
+ protected <T> void registerExtensionPoint(final ExtensionPointName<T> extensionPointName, Class<T> aClass) {
+ super.registerExtensionPoint(extensionPointName, aClass);
+ Disposer.register(myProject, new Disposable() {
+ @Override
+ public void dispose() {
+ Extensions.getRootArea().unregisterExtensionPoint(extensionPointName.getName());
+ }
+ });
+ }
+
+ protected <T> void registerApplicationService(final Class<T> aClass, T object) {
+ getApplication().registerService(aClass, object);
+ Disposer.register(myProject, new Disposable() {
+ @Override
+ public void dispose() {
+ getApplication().getPicoContainer().unregisterComponent(aClass.getName());
+ }
+ });
+ }
+
+ public MockProjectEx getProject() {
+ return myProject;
+ }
+
+ public MockPsiManager getPsiManager() {
+ return myPsiManager;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ myFile = null;
+ myProject = null;
+ myPsiManager = null;
+ }
+
+ protected String getTestDataPath() {
+ return PathManager.getHomePath();
+ }
+
+ @NotNull
+ public final String getTestName() {
+ return getTestName(myLowercaseFirstLetter);
+ }
+
+ protected boolean includeRanges() {
+ return false;
+ }
+
+ protected boolean skipSpaces() {
+ return false;
+ }
+
+ protected boolean checkAllPsiRoots() {
+ return true;
+ }
+
+ protected void doTest(boolean checkResult) {
+ String name = getTestName();
+ try {
+ String text = loadFile(name + "." + myFileExt);
+ myFile = createPsiFile(name, text);
+ ensureParsed(myFile);
+ assertEquals("light virtual file text mismatch", text, ((LightVirtualFile)myFile.getVirtualFile()).getContent().toString());
+ assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(myFile.getVirtualFile()));
+ assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText());
+ assertEquals("psi text mismatch", text, myFile.getText());
+ ensureCorrectReparse(myFile);
+ if (checkResult){
+ checkResult(name, myFile);
+ }
+ else{
+ toParseTreeText(myFile, skipSpaces(), includeRanges());
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void doTest(String suffix) throws IOException {
+ String name = getTestName();
+ String text = loadFile(name + "." + myFileExt);
+ myFile = createPsiFile(name, text);
+ ensureParsed(myFile);
+ assertEquals(text, myFile.getText());
+ checkResult(name + suffix, myFile);
+ }
+
+ protected void doCodeTest(String code) throws IOException {
+ String name = getTestName();
+ myFile = createPsiFile("a", code);
+ ensureParsed(myFile);
+ assertEquals(code, myFile.getText());
+ checkResult(myFilePrefix + name, myFile);
+ }
+
+ protected PsiFile createPsiFile(String name, String text) {
+ return createFile(name + "." + myFileExt, text);
+ }
+
+ protected PsiFile createFile(@NonNls String name, String text) {
+ LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
+ virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
+ return createFile(virtualFile);
+ }
+
+ protected PsiFile createFile(LightVirtualFile virtualFile) {
+ return myFileFactory.trySetupPsiForFile(virtualFile, myLanguage, true, false);
+ }
+
+ protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
+ doCheckResult(myFullDataPath, file, checkAllPsiRoots(), targetDataName, skipSpaces(), includeRanges());
+ }
+
+ public static void doCheckResult(String testDataDir,
+ PsiFile file,
+ boolean checkAllPsiRoots,
+ String targetDataName,
+ boolean skipSpaces,
+ boolean printRanges) throws IOException {
+ FileViewProvider provider = file.getViewProvider();
+ Set<Language> languages = provider.getLanguages();
+
+ if (!checkAllPsiRoots || languages.size() == 1) {
+ doCheckResult(testDataDir, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim());
+ return;
+ }
+
+ for (Language language : languages) {
+ PsiFile root = provider.getPsi(language);
+ String expectedName = targetDataName + "." + language.getID() + ".txt";
+ doCheckResult(testDataDir, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim());
+ }
+ }
+
+ protected void checkResult(String actual) throws IOException {
+ String name = getTestName();
+ doCheckResult(myFullDataPath, myFilePrefix + name + ".txt", actual);
+ }
+
+ protected void checkResult(@TestDataFile @NonNls String targetDataName, String actual) throws IOException {
+ doCheckResult(myFullDataPath, targetDataName, actual);
+ }
+
+ public static void doCheckResult(String fullPath, String targetDataName, String actual) throws IOException {
+ String expectedFileName = fullPath + File.separatorChar + targetDataName;
+ KtUsefulTestCase.assertSameLinesWithFile(expectedFileName, actual);
+ }
+
+ protected static String toParseTreeText(PsiElement file, boolean skipSpaces, boolean printRanges) {
+ return DebugUtil.psiToString(file, skipSpaces, printRanges);
+ }
+
+ protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
+ return loadFileDefault(myFullDataPath, name);
+ }
+
+ public static String loadFileDefault(String dir, String name) throws IOException {
+ return FileUtil.loadFile(new File(dir, name), CharsetToolkit.UTF8, true).trim();
+ }
+
+ public static void ensureParsed(PsiFile file) {
+ file.accept(new PsiElementVisitor() {
+ @Override
+ public void visitElement(PsiElement element) {
+ element.acceptChildren(this);
+ }
+ });
+ }
+
+ public static void ensureCorrectReparse(@NotNull PsiFile file) {
+ String psiToStringDefault = DebugUtil.psiToString(file, false, false);
+ String fileText = file.getText();
+ DiffLog diffLog = (new BlockSupportImpl()).reparseRange(
+ file, file.getNode(), TextRange.allOf(fileText), fileText, new EmptyProgressIndicator(), fileText);
+ diffLog.performActualPsiChange(file);
+
+ TestCase.assertEquals(psiToStringDefault, DebugUtil.psiToString(file, false, false));
+ }
+}
\ No newline at end of file
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
index c3bf76c..f04e03d 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.test.testFramework;
+import com.intellij.codeInsight.CodeInsightSettings;
+import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory;
import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
@@ -23,20 +25,33 @@
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.*;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileVisitor;
+import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.impl.DocumentCommitProcessor;
+import com.intellij.psi.impl.DocumentCommitThread;
+import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.*;
import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
-import com.intellij.util.Consumer;
-import com.intellij.util.ReflectionUtil;
+import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
+import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.hash.HashMap;
+import com.intellij.util.containers.PeekableIterator;
+import com.intellij.util.containers.PeekableIteratorWrapper;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.ui.UIUtil;
import gnu.trove.Equality;
@@ -47,11 +62,11 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
import org.jetbrains.kotlin.types.AbstractTypeChecker;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
import org.junit.Assert;
+import org.junit.ComparisonFailure;
import java.io.File;
import java.io.FileNotFoundException;
@@ -61,14 +76,19 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
-@SuppressWarnings("UseOfSystemOutOrSystemErr")
+/**
+ * @author peter
+ */
+@SuppressWarnings("ALL")
public abstract class KtUsefulTestCase extends TestCase {
public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
- private static final String TEMP_DIR_MARKER = "unitTest_";
+ public static final String TEMP_DIR_MARKER = "unitTest_";
public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
@@ -79,24 +99,34 @@
private Application application;
static {
- IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
- //TODO: investigate and enable
- //IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
+ IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
Logger.setFactory(TestLoggerFactory.class);
}
+ protected static final Logger LOG = Logger.getInstance(KtUsefulTestCase.class);
@NotNull
- protected final Disposable myTestRootDisposable = new TestDisposable();
+ private final Disposable myTestRootDisposable = new TestDisposable();
- private static final String ourPathToKeep = null;
+ static Path ourPathToKeep;
private final List<String> myPathsToKeep = new ArrayList<>();
- private File myTempDir;
+ private String myTempDir;
+ private static final String DEFAULT_SETTINGS_EXTERNALIZED;
+ private static final CodeInsightSettings defaultSettings = new CodeInsightSettings();
static {
// Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
System.setProperty("apple.awt.UIElement", "true");
+ try {
+ Element oldS = new Element("temp");
+ defaultSettings.writeExternal(oldS);
+ DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
// -- KOTLIN ADDITIONAL START --
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
@@ -105,6 +135,42 @@
// -- KOTLIN ADDITIONAL END --
}
+ /**
+ * Pass here the exception you want to be thrown first
+ * E.g.<pre>
+ * {@code
+ * void tearDown() {
+ * try {
+ * doTearDowns();
+ * }
+ * catch(Exception e) {
+ * addSuppressedException(e);
+ * }
+ * finally {
+ * super.tearDown();
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ */
+ protected void addSuppressedException(@NotNull Throwable e) {
+ List<Throwable> list = mySuppressedExceptions;
+ if (list == null) {
+ mySuppressedExceptions = list = new SmartList<>();
+ }
+ list.add(e);
+ }
+ private List<Throwable> mySuppressedExceptions;
+
+
+ public KtUsefulTestCase() {
+ }
+
+ public KtUsefulTestCase(@NotNull String name) {
+ super(name);
+ }
+
protected boolean shouldContainTempFiles() {
return true;
}
@@ -122,11 +188,17 @@
super.setUp();
if (shouldContainTempFiles()) {
- String testName = FileUtil.sanitizeFileName(getTestName(true));
- if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
+ IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ String testName = null;
+ if (policy != null) {
+ testName = policy.getPerTestTempDirName();
+ }
+ if (testName == null) {
+ testName = FileUtil.sanitizeFileName(getTestName(true));
+ }
testName = new File(testName).getName(); // in case the test name contains file separators
- myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
- FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
+ myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER + testName, "", false).getPath();
+ FileUtil.resetCanonicalTempPathCache(myTempDir);
}
boolean isStressTest = isStressTest();
@@ -137,6 +209,16 @@
// turn off Disposer debugging for performance tests
Disposer.setDebugMode(!isStressTest);
+
+ if (isIconRequired()) {
+ // ensure that IconLoader will use dummy empty icon
+ IconLoader.deactivate();
+ //IconManager.activate();
+ }
+ }
+
+ protected boolean isIconRequired() {
+ return false;
}
@Override
@@ -145,6 +227,11 @@
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll(
+ () -> {
+ if (isIconRequired()) {
+ //IconManager.deactivate();
+ }
+ },
() -> disposeRootDisposable(),
() -> cleanupSwingDataStructures(),
() -> cleanupDeleteOnExitHookList(),
@@ -153,7 +240,7 @@
if (shouldContainTempFiles()) {
FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
if (hasTmpFilesToKeep()) {
- File[] files = myTempDir.listFiles();
+ File[] files = new File(myTempDir).listFiles();
if (files != null) {
for (File file : files) {
if (!shouldKeepTmpFile(file)) {
@@ -163,15 +250,14 @@
}
}
else {
- FileUtil.delete(myTempDir);
+ FileUtil.delete(new File(myTempDir));
}
}
},
- () -> UIUtil.removeLeakingAppleListeners()
- ).run();
+ () -> waitForAppLeakingThreads(10, TimeUnit.SECONDS)
+ ).run(ObjectUtils.notNull(mySuppressedExceptions, Collections.emptyList()));
}
finally {
- super.tearDown();
// -- KOTLIN ADDITIONAL START --
TestApplicationUtilKt.resetApplicationToNull(application);
application = null;
@@ -188,12 +274,12 @@
}
private boolean hasTmpFilesToKeep() {
- return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
+ return ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep.toString(), false) || !myPathsToKeep.isEmpty();
}
private boolean shouldKeepTmpFile(@NotNull File file) {
String path = file.getPath();
- if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
+ if (FileUtil.pathsEqual(path, ourPathToKeep.toString())) return true;
for (String pathToKeep : myPathsToKeep) {
if (FileUtil.pathsEqual(path, pathToKeep)) return true;
}
@@ -201,7 +287,7 @@
}
private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
- private static final Class DELETE_ON_EXIT_HOOK_CLASS;
+ private static final Class<?> DELETE_ON_EXIT_HOOK_CLASS;
static {
Class<?> aClass;
try {
@@ -237,12 +323,45 @@
@SuppressWarnings("ConstantConditions")
private static void cleanupSwingDataStructures() throws Exception {
Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
- Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
+ Map<?, ?> componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
componentKeyStrokeMap.clear();
- Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
+ Map<?, ?> containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
containerMap.clear();
}
+ static void doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings) {
+ final CodeInsightSettings settings = CodeInsightSettings.getInstance();
+ // don't use method references here to make stack trace reading easier
+ //noinspection Convert2MethodRef
+ new RunAll()
+ .append(() -> {
+ try {
+ checkCodeInsightSettingsEqual(defaultSettings, settings);
+ }
+ catch (AssertionError error) {
+ CodeInsightSettings clean = new CodeInsightSettings();
+ for (Field field : clean.getClass().getFields()) {
+ try {
+ ReflectionUtil.copyFieldValue(clean, settings, field);
+ }
+ catch (Exception ignored) {
+ }
+ }
+ throw error;
+ }
+ })
+ .append(() -> {
+ currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
+ try {
+ checkCodeStyleSettingsEqual(oldCodeStyleSettings, currentCodeStyleSettings);
+ }
+ finally {
+ currentCodeStyleSettings.clearCodeStyleSettings();
+ }
+ })
+ .run();
+ }
+
@NotNull
public Disposable getTestRootDisposable() {
return myTestRootDisposable;
@@ -252,13 +371,11 @@
protected void runTest() throws Throwable {
final Throwable[] throwables = new Throwable[1];
- AtomicBoolean completed = new AtomicBoolean(false);
Runnable runnable = () -> {
try {
- //TestLoggerFactory.onTestStarted();
+ TestLoggerFactory.onTestStarted();
super.runTest();
TestLoggerFactory.onTestFinished(true);
- completed.set(true);
}
catch (InvocationTargetException e) {
TestLoggerFactory.onTestFinished(false);
@@ -281,9 +398,6 @@
if (throwables[0] != null) {
throw throwables[0];
}
- if (!completed.get()) {
- throw new IllegalStateException("test didn't start");
- }
}
protected boolean shouldRunTest() {
@@ -291,19 +405,18 @@
}
protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
- //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
- //if (policy != null && !policy.runInDispatchThread()) {
- // runnable.run();
- //}
- //else {
+ if (runInDispatchThread()) {
EdtTestUtilKt.runInEdtAndWait(() -> {
runnable.run();
return null;
});
- //}
+ }
+ else {
+ runnable.run();
+ }
}
- private void defaultRunBare() throws Throwable {
+ protected void defaultRunBare() throws Throwable {
Throwable exception = null;
try {
long setupStart = System.nanoTime();
@@ -324,11 +437,17 @@
logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
}
catch (Throwable tearingDown) {
- if (exception == null) exception = tearingDown;
- else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
+ if (exception == null) {
+ exception = tearingDown;
+ }
+ else {
+ exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
+ }
}
}
- if (exception != null) throw exception;
+ if (exception != null) {
+ throw exception;
+ }
}
/**
@@ -368,7 +487,7 @@
if (runInDispatchThread()) {
TestRunnerUtil.replaceIdeEventQueueSafely();
- com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
+ EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
}
else {
defaultRunBare();
@@ -376,13 +495,20 @@
}
protected boolean runInDispatchThread() {
- //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
- //if (policy != null) {
- // return policy.runInDispatchThread();
- //}
+ IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ if (policy != null) {
+ return policy.runInDispatchThread();
+ }
return true;
}
+ /**
+ * If you want a more shorter name than runInEdtAndWait.
+ */
+ protected void edt(@NotNull ThrowableRunnable<Throwable> runnable) {
+ EdtTestUtil.runInEdtAndWait(runnable);
+ }
+
@NotNull
public static String toString(@NotNull Iterable<?> collection) {
if (!collection.iterator().hasNext()) {
@@ -515,9 +641,20 @@
}
public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
- ArrayList<T> copy = new ArrayList<>(collection);
- copy.retainAll(expected);
- assertOrderedEquals(toString(collection), copy, expected);
+ PeekableIterator<T> expectedIt = new PeekableIteratorWrapper<>(expected.iterator());
+ PeekableIterator<T> actualIt = new PeekableIteratorWrapper<>(collection.iterator());
+
+ while (actualIt.hasNext() && expectedIt.hasNext()) {
+ T expectedElem = expectedIt.peek();
+ T actualElem = actualIt.peek();
+ if (expectedElem.equals(actualElem)) {
+ expectedIt.next();
+ }
+ actualIt.next();
+ }
+ if (expectedIt.hasNext()) {
+ throw new ComparisonFailure("", toString(expected), toString(collection));
+ }
}
@SafeVarargs
@@ -592,7 +729,7 @@
if (collection.size() != checkers.length) {
Assert.fail(toString(collection));
}
- Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
+ Set<Consumer<T>> checkerSet = ContainerUtil.set(checkers);
int i = 0;
Throwable lastError = null;
for (final T actual : collection) {
@@ -767,7 +904,7 @@
//noinspection UseOfSystemOutOrSystemErr
System.out.println("File " + filePath + " created.");
}
- fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
+ fileText = FileUtil.loadFile(new File(filePath), StandardCharsets.UTF_8);
}
catch (FileNotFoundException e) {
VfsTestUtil.overwriteTestData(filePath, actualText);
@@ -784,14 +921,14 @@
}
protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
- Class aClass = test.getClass();
+ Class<?> aClass = test.getClass();
while (aClass != null) {
clearDeclaredFields(test, aClass);
aClass = aClass.getSuperclass();
}
}
- public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
+ public static void clearDeclaredFields(@NotNull Object test, @NotNull Class<?> aClass) throws IllegalAccessException {
for (final Field field : aClass.getDeclaredFields()) {
final String name = field.getDeclaringClass().getName();
if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
@@ -817,6 +954,14 @@
}
}
+ private static void checkCodeInsightSettingsEqual(@NotNull CodeInsightSettings oldSettings, @NotNull CodeInsightSettings settings) {
+ if (!oldSettings.equals(settings)) {
+ Element newS = new Element("temp");
+ settings.writeExternal(newS);
+ Assert.assertEquals("Code insight settings damaged", DEFAULT_SETTINGS_EXTERNALIZED, JDOMUtil.writeElement(newS));
+ }
+ }
+
public boolean isPerformanceTest() {
String testName = getName();
String className = getClass().getSimpleName();
@@ -843,6 +988,21 @@
return name != null && (name.contains("Stress") || name.contains("Slow"));
}
+ public static void doPostponedFormatting(@NotNull Project project) {
+ DocumentUtil.writeInRunUndoTransparentAction(() -> {
+ PsiDocumentManager.getInstance(project).commitAllDocuments();
+ PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
+ });
+ }
+
+ /**
+ * Checks that code block throw corresponding exception.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ */
+ protected void assertException(@NotNull AbstractExceptionCase<?> exceptionCase) {
+ assertException(exceptionCase, null);
+ }
/**
* Checks that code block throw corresponding exception with expected error msg.
@@ -857,6 +1017,42 @@
}
/**
+ * Checks that the code block throws an exception of the specified class.
+ *
+ * @param exceptionClass Expected exception type
+ * @param runnable Block annotated with some exception type
+ */
+ public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
+ @NotNull ThrowableRunnable<T> runnable) {
+ assertThrows(exceptionClass, null, runnable);
+ }
+
+ /**
+ * Checks that the code block throws an exception of the specified class with expected error msg.
+ * If expected error message is null it will not be checked.
+ *
+ * @param exceptionClass Expected exception type
+ * @param expectedErrorMsgPart expected error message, of any
+ * @param runnable Block annotated with some exception type
+ */
+ @SuppressWarnings({"unchecked", "SameParameterValue"})
+ public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
+ @Nullable String expectedErrorMsgPart,
+ @NotNull ThrowableRunnable<T> runnable) {
+ assertExceptionOccurred(true, new AbstractExceptionCase() {
+ @Override
+ public Class<Throwable> getExpectedExceptionClass() {
+ return (Class<Throwable>)exceptionClass;
+ }
+
+ @Override
+ public void tryClosure() throws Throwable {
+ runnable.run();
+ }
+ }, expectedErrorMsgPart);
+ }
+
+ /**
* Checks that code block doesn't throw corresponding exception.
*
* @param exceptionCase Block annotated with some exception type
@@ -878,21 +1074,22 @@
private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
@NotNull AbstractExceptionCase<T> exceptionCase,
- String expectedErrorMsg) throws T {
+ String expectedErrorMsgPart) throws T {
boolean wasThrown = false;
try {
exceptionCase.tryClosure();
}
catch (Throwable e) {
+ Throwable cause = e;
+
if (shouldOccur) {
wasThrown = true;
- final String errorMessage = exceptionCase.getAssertionErrorMessage();
- assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
- if (expectedErrorMsg != null) {
- assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
+ assertInstanceOf(cause, exceptionCase.getExpectedExceptionClass());
+ if (expectedErrorMsgPart != null) {
+ assertTrue(cause.getMessage(), cause.getMessage().contains(expectedErrorMsgPart));
}
}
- else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
+ else if (exceptionCase.getExpectedExceptionClass().equals(cause.getClass())) {
wasThrown = true;
//noinspection UseOfSystemOutOrSystemErr
@@ -900,7 +1097,7 @@
//noinspection UseOfSystemOutOrSystemErr
e.printStackTrace(System.out);
- fail("Exception isn't expected here. Exception message: " + e.getMessage());
+ fail("Exception isn't expected here. Exception message: " + cause.getMessage());
}
else {
throw e;
@@ -908,7 +1105,7 @@
}
finally {
if (shouldOccur && !wasThrown) {
- fail(exceptionCase.getAssertionErrorMessage());
+ fail(exceptionCase.getExpectedExceptionClass().getName() + " must be thrown.");
}
}
}
@@ -937,7 +1134,7 @@
}
public static void refreshRecursively(@NotNull VirtualFile file) {
- VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
+ VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
file.getChildren();
@@ -947,11 +1144,27 @@
file.refresh(false, true);
}
- @Nullable
public static VirtualFile refreshAndFindFile(@NotNull final File file) {
return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
}
+ public static void waitForAppLeakingThreads(long timeout, @NotNull TimeUnit timeUnit) {
+ EdtTestUtil.runInEdtAndWait(() -> {
+ Application app = ApplicationManager.getApplication();
+ if (app != null && !app.isDisposed()) {
+ FileBasedIndexImpl index = (FileBasedIndexImpl)app.getServiceIfCreated(FileBasedIndex.class);
+ if (index != null) {
+ index.getChangedFilesCollector().waitForVfsEventsExecuted(timeout, timeUnit);
+ }
+
+ DocumentCommitThread commitThread = (DocumentCommitThread)app.getServiceIfCreated(DocumentCommitProcessor.class);
+ if (commitThread != null) {
+ commitThread.waitForAllCommits(timeout, timeUnit);
+ }
+ }
+ });
+ }
+
protected class TestDisposable implements Disposable {
private volatile boolean myDisposed;
@@ -972,5 +1185,5 @@
String testName = getTestName(false);
return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
}
- };
-}
+ }
+}
\ No newline at end of file
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193 b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193
new file mode 100644
index 0000000..c3bf76c
--- /dev/null
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193
@@ -0,0 +1,976 @@
+/*
+ * 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.test.testFramework;
+
+import com.intellij.diagnostic.PerformanceWatcher;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.impl.ApplicationInfoImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.*;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.rt.execution.junit.FileComparisonFailure;
+import com.intellij.testFramework.*;
+import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
+import com.intellij.util.Consumer;
+import com.intellij.util.ReflectionUtil;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.hash.HashMap;
+import com.intellij.util.lang.CompoundRuntimeException;
+import com.intellij.util.ui.UIUtil;
+import gnu.trove.Equality;
+import gnu.trove.THashSet;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import org.jdom.Element;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
+import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
+import org.jetbrains.kotlin.types.AbstractTypeChecker;
+import org.jetbrains.kotlin.types.FlexibleTypeImpl;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
+public abstract class KtUsefulTestCase extends TestCase {
+ public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
+ private static final String TEMP_DIR_MARKER = "unitTest_";
+ public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
+
+ private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
+
+ private static final Map<String, Long> TOTAL_SETUP_COST_MILLIS = new HashMap<>();
+ private static final Map<String, Long> TOTAL_TEARDOWN_COST_MILLIS = new HashMap<>();
+
+ private Application application;
+
+ static {
+ IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
+ //TODO: investigate and enable
+ //IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
+ Logger.setFactory(TestLoggerFactory.class);
+ }
+
+ @NotNull
+ protected final Disposable myTestRootDisposable = new TestDisposable();
+
+ private static final String ourPathToKeep = null;
+ private final List<String> myPathsToKeep = new ArrayList<>();
+
+ private File myTempDir;
+
+ static {
+ // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
+ System.setProperty("apple.awt.UIElement", "true");
+
+ // -- KOTLIN ADDITIONAL START --
+
+ FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
+ AbstractTypeChecker.RUN_SLOW_ASSERTIONS = true;
+
+ // -- KOTLIN ADDITIONAL END --
+ }
+
+ protected boolean shouldContainTempFiles() {
+ return true;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ // -- KOTLIN ADDITIONAL START --
+ application = ApplicationManager.getApplication();
+
+ if (application != null && application.isDisposed()) {
+ MockComponentManagerCreationTracer.diagnoseDisposedButNotClearedApplication(application);
+ }
+ // -- KOTLIN ADDITIONAL END --
+
+ super.setUp();
+
+ if (shouldContainTempFiles()) {
+ String testName = FileUtil.sanitizeFileName(getTestName(true));
+ if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
+ testName = new File(testName).getName(); // in case the test name contains file separators
+ myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
+ FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
+ }
+
+ boolean isStressTest = isStressTest();
+ ApplicationInfoImpl.setInStressTest(isStressTest);
+ if (isPerformanceTest()) {
+ Timings.getStatistics();
+ }
+
+ // turn off Disposer debugging for performance tests
+ Disposer.setDebugMode(!isStressTest);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ // don't use method references here to make stack trace reading easier
+ //noinspection Convert2MethodRef
+ new RunAll(
+ () -> disposeRootDisposable(),
+ () -> cleanupSwingDataStructures(),
+ () -> cleanupDeleteOnExitHookList(),
+ () -> Disposer.setDebugMode(true),
+ () -> {
+ if (shouldContainTempFiles()) {
+ FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
+ if (hasTmpFilesToKeep()) {
+ File[] files = myTempDir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (!shouldKeepTmpFile(file)) {
+ FileUtil.delete(file);
+ }
+ }
+ }
+ }
+ else {
+ FileUtil.delete(myTempDir);
+ }
+ }
+ },
+ () -> UIUtil.removeLeakingAppleListeners()
+ ).run();
+ }
+ finally {
+ super.tearDown();
+ // -- KOTLIN ADDITIONAL START --
+ TestApplicationUtilKt.resetApplicationToNull(application);
+ application = null;
+ // -- KOTLIN ADDITIONAL END --
+ }
+ }
+
+ protected final void disposeRootDisposable() {
+ Disposer.dispose(getTestRootDisposable());
+ }
+
+ protected void addTmpFileToKeep(@NotNull File file) {
+ myPathsToKeep.add(file.getPath());
+ }
+
+ private boolean hasTmpFilesToKeep() {
+ return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
+ }
+
+ private boolean shouldKeepTmpFile(@NotNull File file) {
+ String path = file.getPath();
+ if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
+ for (String pathToKeep : myPathsToKeep) {
+ if (FileUtil.pathsEqual(path, pathToKeep)) return true;
+ }
+ return false;
+ }
+
+ private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
+ private static final Class DELETE_ON_EXIT_HOOK_CLASS;
+ static {
+ Class<?> aClass;
+ try {
+ aClass = Class.forName("java.io.DeleteOnExitHook");
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ @SuppressWarnings("unchecked") Set<String> files = ReflectionUtil.getStaticFieldValue(aClass, Set.class, "files");
+ DELETE_ON_EXIT_HOOK_CLASS = aClass;
+ DELETE_ON_EXIT_HOOK_DOT_FILES = files;
+ }
+
+ @SuppressWarnings("SynchronizeOnThis")
+ private static void cleanupDeleteOnExitHookList() {
+ // try to reduce file set retained by java.io.DeleteOnExitHook
+ List<String> list;
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ if (DELETE_ON_EXIT_HOOK_DOT_FILES.isEmpty()) return;
+ list = new ArrayList<>(DELETE_ON_EXIT_HOOK_DOT_FILES);
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ String path = list.get(i);
+ File file = new File(path);
+ if (file.delete() || !file.exists()) {
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ DELETE_ON_EXIT_HOOK_DOT_FILES.remove(path);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ private static void cleanupSwingDataStructures() throws Exception {
+ Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
+ Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
+ componentKeyStrokeMap.clear();
+ Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
+ containerMap.clear();
+ }
+
+ @NotNull
+ public Disposable getTestRootDisposable() {
+ return myTestRootDisposable;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ final Throwable[] throwables = new Throwable[1];
+
+ AtomicBoolean completed = new AtomicBoolean(false);
+ Runnable runnable = () -> {
+ try {
+ //TestLoggerFactory.onTestStarted();
+ super.runTest();
+ TestLoggerFactory.onTestFinished(true);
+ completed.set(true);
+ }
+ catch (InvocationTargetException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e;
+ }
+ catch (Throwable e) {
+ TestLoggerFactory.onTestFinished(false);
+ throwables[0] = e;
+ }
+ };
+
+ invokeTestRunnable(runnable);
+
+ if (throwables[0] != null) {
+ throw throwables[0];
+ }
+ if (!completed.get()) {
+ throw new IllegalStateException("test didn't start");
+ }
+ }
+
+ protected boolean shouldRunTest() {
+ return TestFrameworkUtil.canRunTest(getClass());
+ }
+
+ protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
+ //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ //if (policy != null && !policy.runInDispatchThread()) {
+ // runnable.run();
+ //}
+ //else {
+ EdtTestUtilKt.runInEdtAndWait(() -> {
+ runnable.run();
+ return null;
+ });
+ //}
+ }
+
+ private void defaultRunBare() throws Throwable {
+ Throwable exception = null;
+ try {
+ long setupStart = System.nanoTime();
+ setUp();
+ long setupCost = (System.nanoTime() - setupStart) / 1000000;
+ logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS);
+
+ runTest();
+ }
+ catch (Throwable running) {
+ exception = running;
+ }
+ finally {
+ try {
+ long teardownStart = System.nanoTime();
+ tearDown();
+ long teardownCost = (System.nanoTime() - teardownStart) / 1000000;
+ logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
+ }
+ catch (Throwable tearingDown) {
+ if (exception == null) exception = tearingDown;
+ else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
+ }
+ }
+ if (exception != null) throw exception;
+ }
+
+ /**
+ * Logs the setup cost grouped by test fixture class (superclass of the current test class).
+ *
+ * @param cost setup cost in milliseconds
+ */
+ private void logPerClassCost(long cost, @NotNull Map<String, Long> costMap) {
+ Class<?> superclass = getClass().getSuperclass();
+ Long oldCost = costMap.get(superclass.getName());
+ long newCost = oldCost == null ? cost : oldCost + cost;
+ costMap.put(superclass.getName(), newCost);
+ }
+
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
+ static void logSetupTeardownCosts() {
+ System.out.println("Setup costs");
+ long totalSetup = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_SETUP_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalSetup += entry.getValue();
+ }
+ System.out.println("Teardown costs");
+ long totalTeardown = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_TEARDOWN_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalTeardown += entry.getValue();
+ }
+ System.out.println(String.format("Total overhead: setup %d ms, teardown %d ms", totalSetup, totalTeardown));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalSetupMs' value='%d']", totalSetup));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTeardownMs' value='%d']", totalTeardown));
+ }
+
+ @Override
+ public void runBare() throws Throwable {
+ if (!shouldRunTest()) return;
+
+ if (runInDispatchThread()) {
+ TestRunnerUtil.replaceIdeEventQueueSafely();
+ com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
+ }
+ else {
+ defaultRunBare();
+ }
+ }
+
+ protected boolean runInDispatchThread() {
+ //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ //if (policy != null) {
+ // return policy.runInDispatchThread();
+ //}
+ return true;
+ }
+
+ @NotNull
+ public static String toString(@NotNull Iterable<?> collection) {
+ if (!collection.iterator().hasNext()) {
+ return "<empty>";
+ }
+
+ final StringBuilder builder = new StringBuilder();
+ for (final Object o : collection) {
+ if (o instanceof THashSet) {
+ builder.append(new TreeSet<>((THashSet<?>)o));
+ }
+ else {
+ builder.append(o);
+ }
+ builder.append('\n');
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull T[] actual, @NotNull T... expected) {
+ assertOrderedEquals(Arrays.asList(actual), expected);
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static void assertOrderedEquals(@NotNull byte[] actual, @NotNull byte[] expected) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < actual.length; i++) {
+ byte a = actual[i];
+ byte e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ public static void assertOrderedEquals(@NotNull int[] actual, @NotNull int[] expected) {
+ if (actual.length != expected.length) {
+ fail("Expected size: "+expected.length+"; actual: "+actual.length+"\nexpected: "+Arrays.toString(expected)+"\nactual : "+Arrays.toString(actual));
+ }
+ for (int i = 0; i < actual.length; i++) {
+ int a = actual[i];
+ int e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg, @NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals(errorMsg, actual, Arrays.asList(expected));
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull Iterable<? extends T> expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected) {
+ //noinspection unchecked
+ assertOrderedEquals(errorMsg, actual, expected, Equality.CANONICAL);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected,
+ @NotNull Equality<? super T> comparator) {
+ if (!equals(actual, expected, comparator)) {
+ String expectedString = toString(expected);
+ String actualString = toString(actual);
+ Assert.assertEquals(errorMsg, expectedString, actualString);
+ Assert.fail("Warning! 'toString' does not reflect the difference.\nExpected: " + expectedString + "\nActual: " + actualString);
+ }
+ }
+
+ private static <T> boolean equals(@NotNull Iterable<? extends T> a1,
+ @NotNull Iterable<? extends T> a2,
+ @NotNull Equality<? super T> comparator) {
+ Iterator<? extends T> it1 = a1.iterator();
+ Iterator<? extends T> it2 = a2.iterator();
+ while (it1.hasNext() || it2.hasNext()) {
+ if (!it1.hasNext() || !it2.hasNext()) return false;
+ if (!comparator.equals(it1.next(), it2.next())) return false;
+ }
+ return true;
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertOrderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull T[] actual, @NotNull T... expected) {
+ assertSameElements(Arrays.asList(actual), expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull T... expected) {
+ assertSameElements(actual, Arrays.asList(expected));
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ assertSameElements("", actual, expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull String message, @NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ if (actual.size() != expected.size() || !new HashSet<>(expected).equals(new HashSet<T>(actual))) {
+ Assert.assertEquals(message, new HashSet<>(expected), new HashSet<T>(actual));
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsOrdered(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ ArrayList<T> copy = new ArrayList<>(collection);
+ copy.retainAll(expected);
+ assertOrderedEquals(toString(collection), copy, expected);
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsElements(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ ArrayList<T> copy = new ArrayList<>(collection);
+ copy.retainAll(expected);
+ assertSameElements(toString(collection), copy, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Object[] collection, @NotNull String separator) {
+ return toString(Arrays.asList(collection), separator);
+ }
+
+ @SafeVarargs
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull T... notExpected) {
+ assertDoesntContain(collection, Arrays.asList(notExpected));
+ }
+
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> notExpected) {
+ ArrayList<T> expected = new ArrayList<>(collection);
+ expected.removeAll(notExpected);
+ assertSameElements(collection, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Collection<?> collection, @NotNull String separator) {
+ List<String> list = ContainerUtil.map2List(collection, String::valueOf);
+ Collections.sort(list);
+ StringBuilder builder = new StringBuilder();
+ boolean flag = false;
+ for (final String o : list) {
+ if (flag) {
+ builder.append(separator);
+ }
+ builder.append(o);
+ flag = true;
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ int i = 0;
+ for (final T actual : collection) {
+ try {
+ checkers[i].consume(actual);
+ }
+ catch (AssertionFailedError e) {
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println(i + ": " + actual);
+ throw e;
+ }
+ i++;
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertUnorderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
+ int i = 0;
+ Throwable lastError = null;
+ for (final T actual : collection) {
+ boolean flag = true;
+ for (final Consumer<T> condition : checkerSet) {
+ Throwable error = accepts(condition, actual);
+ if (error == null) {
+ checkerSet.remove(condition);
+ flag = false;
+ break;
+ }
+ else {
+ lastError = error;
+ }
+ }
+ if (flag) {
+ //noinspection ConstantConditions,CallToPrintStackTrace
+ lastError.printStackTrace();
+ Assert.fail("Incorrect element(" + i + "): " + actual);
+ }
+ i++;
+ }
+ }
+
+ private static <T> Throwable accepts(@NotNull Consumer<? super T> condition, final T actual) {
+ try {
+ condition.consume(actual);
+ return null;
+ }
+ catch (Throwable e) {
+ return e;
+ }
+ }
+
+ @Contract("null, _ -> fail")
+ @NotNull
+ public static <T> T assertInstanceOf(Object o, @NotNull Class<T> aClass) {
+ Assert.assertNotNull("Expected instance of: " + aClass.getName() + " actual: " + null, o);
+ Assert.assertTrue("Expected instance of: " + aClass.getName() + " actual: " + o.getClass().getName(), aClass.isInstance(o));
+ @SuppressWarnings("unchecked") T t = (T)o;
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull Collection<? extends T> collection) {
+ Iterator<? extends T> iterator = collection.iterator();
+ String toString = toString(collection);
+ Assert.assertTrue(toString, iterator.hasNext());
+ T t = iterator.next();
+ Assert.assertFalse(toString, iterator.hasNext());
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull T[] ts) {
+ Assert.assertEquals(Arrays.asList(ts).toString(), 1, ts.length);
+ return ts[0];
+ }
+
+ @SafeVarargs
+ public static <T> void assertOneOf(T value, @NotNull T... values) {
+ for (T v : values) {
+ if (Objects.equals(value, v)) {
+ return;
+ }
+ }
+ Assert.fail(value + " should be equal to one of " + Arrays.toString(values));
+ }
+
+ public static void printThreadDump() {
+ PerformanceWatcher.dumpThreadsToConsole("Thread dump:");
+ }
+
+ public static void assertEmpty(@NotNull Object[] array) {
+ assertOrderedEquals(array);
+ }
+
+ public static void assertNotEmpty(final Collection<?> collection) {
+ assertNotNull(collection);
+ assertFalse(collection.isEmpty());
+ }
+
+ public static void assertEmpty(@NotNull Collection<?> collection) {
+ assertEmpty(collection.toString(), collection);
+ }
+
+ public static void assertNullOrEmpty(@Nullable Collection<?> collection) {
+ if (collection == null) return;
+ assertEmpty("", collection);
+ }
+
+ public static void assertEmpty(final String s) {
+ assertTrue(s, StringUtil.isEmpty(s));
+ }
+
+ public static <T> void assertEmpty(@NotNull String errorMsg, @NotNull Collection<? extends T> collection) {
+ assertOrderedEquals(errorMsg, collection, Collections.emptyList());
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Object[] array) {
+ if (array.length != expectedSize) {
+ assertEquals(toString(Arrays.asList(array)), expectedSize, array.length);
+ }
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Collection<?> c) {
+ if (c.size() != expectedSize) {
+ assertEquals(toString(c), expectedSize, c.size());
+ }
+ }
+
+ @NotNull
+ protected <T extends Disposable> T disposeOnTearDown(@NotNull T disposable) {
+ Disposer.register(getTestRootDisposable(), disposable);
+ return disposable;
+ }
+
+ public static void assertSameLines(@NotNull String expected, @NotNull String actual) {
+ assertSameLines(null, expected, actual);
+ }
+
+ public static void assertSameLines(@Nullable String message, @NotNull String expected, @NotNull String actual) {
+ String expectedText = StringUtil.convertLineSeparators(expected.trim());
+ String actualText = StringUtil.convertLineSeparators(actual.trim());
+ Assert.assertEquals(message, expectedText, actualText);
+ }
+
+ public static void assertExists(@NotNull File file){
+ assertTrue("File should exist " + file, file.exists());
+ }
+
+ public static void assertDoesntExist(@NotNull File file){
+ assertFalse("File should not exist " + file, file.exists());
+ }
+
+ @NotNull
+ protected String getTestName(boolean lowercaseFirstLetter) {
+ return getTestName(getName(), lowercaseFirstLetter);
+ }
+
+ @NotNull
+ public static String getTestName(@Nullable String name, boolean lowercaseFirstLetter) {
+ return name == null ? "" : PlatformTestUtil.getTestName(name, lowercaseFirstLetter);
+ }
+
+ @NotNull
+ protected String getTestDirectoryName() {
+ final String testName = getTestName(true);
+ return testName.replaceAll("_.*", "");
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText) {
+ assertSameLinesWithFile(filePath, actualText, true);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ @NotNull Supplier<String> messageProducer) {
+ assertSameLinesWithFile(filePath, actualText, true, messageProducer);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText, boolean trimBeforeComparing) {
+ assertSameLinesWithFile(filePath, actualText, trimBeforeComparing, null);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ boolean trimBeforeComparing,
+ @Nullable Supplier<String> messageProducer) {
+ String fileText;
+ try {
+ if (OVERWRITE_TESTDATA) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println("File " + filePath + " created.");
+ }
+ fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
+ }
+ catch (FileNotFoundException e) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ throw new AssertionFailedError("No output text found. File " + filePath + " created.");
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ String expected = StringUtil.convertLineSeparators(trimBeforeComparing ? fileText.trim() : fileText);
+ String actual = StringUtil.convertLineSeparators(trimBeforeComparing ? actualText.trim() : actualText);
+ if (!Comparing.equal(expected, actual)) {
+ throw new FileComparisonFailure(messageProducer == null ? null : messageProducer.get(), expected, actual, filePath);
+ }
+ }
+
+ protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
+ Class aClass = test.getClass();
+ while (aClass != null) {
+ clearDeclaredFields(test, aClass);
+ aClass = aClass.getSuperclass();
+ }
+ }
+
+ public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
+ for (final Field field : aClass.getDeclaredFields()) {
+ final String name = field.getDeclaringClass().getName();
+ if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
+ final int modifiers = field.getModifiers();
+ if ((modifiers & Modifier.FINAL) == 0 && (modifiers & Modifier.STATIC) == 0 && !field.getType().isPrimitive()) {
+ field.setAccessible(true);
+ field.set(test, null);
+ }
+ }
+ }
+ }
+
+ private static void checkCodeStyleSettingsEqual(@NotNull CodeStyleSettings expected, @NotNull CodeStyleSettings settings) {
+ if (!expected.equals(settings)) {
+ Element oldS = new Element("temp");
+ expected.writeExternal(oldS);
+ Element newS = new Element("temp");
+ settings.writeExternal(newS);
+
+ String newString = JDOMUtil.writeElement(newS);
+ String oldString = JDOMUtil.writeElement(oldS);
+ Assert.assertEquals("Code style settings damaged", oldString, newString);
+ }
+ }
+
+ public boolean isPerformanceTest() {
+ String testName = getName();
+ String className = getClass().getSimpleName();
+ return TestFrameworkUtil.isPerformanceTest(testName, className);
+ }
+
+ /**
+ * @return true for a test which performs A LOT of computations.
+ * Such test should typically avoid performing expensive checks, e.g. data structure consistency complex validations.
+ * If you want your test to be treated as "Stress", please mention one of these words in its name: "Stress", "Slow".
+ * For example: {@code public void testStressPSIFromDifferentThreads()}
+ */
+ public boolean isStressTest() {
+ return isStressTest(getName(), getClass().getName());
+ }
+
+ private static boolean isStressTest(String testName, String className) {
+ return TestFrameworkUtil.isPerformanceTest(testName, className) ||
+ containsStressWords(testName) ||
+ containsStressWords(className);
+ }
+
+ private static boolean containsStressWords(@Nullable String name) {
+ return name != null && (name.contains("Stress") || name.contains("Slow"));
+ }
+
+
+ /**
+ * Checks that code block throw corresponding exception with expected error msg.
+ * If expected error message is null it will not be checked.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ * @param expectedErrorMsg expected error message
+ */
+ protected void assertException(@NotNull AbstractExceptionCase exceptionCase, @Nullable String expectedErrorMsg) {
+ //noinspection unchecked
+ assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
+ }
+
+ /**
+ * Checks that code block doesn't throw corresponding exception.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ */
+ protected <T extends Throwable> void assertNoException(@NotNull AbstractExceptionCase<T> exceptionCase) throws T {
+ assertExceptionOccurred(false, exceptionCase, null);
+ }
+
+ protected void assertNoThrowable(@NotNull Runnable closure) {
+ String throwableName = null;
+ try {
+ closure.run();
+ }
+ catch (Throwable thr) {
+ throwableName = thr.getClass().getName();
+ }
+ assertNull(throwableName);
+ }
+
+ private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
+ @NotNull AbstractExceptionCase<T> exceptionCase,
+ String expectedErrorMsg) throws T {
+ boolean wasThrown = false;
+ try {
+ exceptionCase.tryClosure();
+ }
+ catch (Throwable e) {
+ if (shouldOccur) {
+ wasThrown = true;
+ final String errorMessage = exceptionCase.getAssertionErrorMessage();
+ assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
+ if (expectedErrorMsg != null) {
+ assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
+ }
+ }
+ else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
+ wasThrown = true;
+
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println();
+ //noinspection UseOfSystemOutOrSystemErr
+ e.printStackTrace(System.out);
+
+ fail("Exception isn't expected here. Exception message: " + e.getMessage());
+ }
+ else {
+ throw e;
+ }
+ }
+ finally {
+ if (shouldOccur && !wasThrown) {
+ fail(exceptionCase.getAssertionErrorMessage());
+ }
+ }
+ }
+
+ protected boolean annotatedWith(@NotNull Class<? extends Annotation> annotationClass) {
+ Class<?> aClass = getClass();
+ String methodName = "test" + getTestName(false);
+ boolean methodChecked = false;
+ while (aClass != null && aClass != Object.class) {
+ if (aClass.getAnnotation(annotationClass) != null) return true;
+ if (!methodChecked) {
+ Method method = ReflectionUtil.getDeclaredMethod(aClass, methodName);
+ if (method != null) {
+ if (method.getAnnotation(annotationClass) != null) return true;
+ methodChecked = true;
+ }
+ }
+ aClass = aClass.getSuperclass();
+ }
+ return false;
+ }
+
+ @NotNull
+ protected String getHomePath() {
+ return PathManager.getHomePath().replace(File.separatorChar, '/');
+ }
+
+ public static void refreshRecursively(@NotNull VirtualFile file) {
+ VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
+ @Override
+ public boolean visitFile(@NotNull VirtualFile file) {
+ file.getChildren();
+ return true;
+ }
+ });
+ file.refresh(false, true);
+ }
+
+ @Nullable
+ public static VirtualFile refreshAndFindFile(@NotNull final File file) {
+ return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
+ }
+
+ protected class TestDisposable implements Disposable {
+ private volatile boolean myDisposed;
+
+ public TestDisposable() {
+ }
+
+ @Override
+ public void dispose() {
+ myDisposed = true;
+ }
+
+ public boolean isDisposed() {
+ return myDisposed;
+ }
+
+ @Override
+ public String toString() {
+ String testName = getTestName(false);
+ return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
+ }
+ };
+}
diff --git a/gradle/versions.properties b/gradle/versions.properties
index 0d985de..7b464ab 100644
--- a/gradle/versions.properties
+++ b/gradle/versions.properties
@@ -1,18 +1,18 @@
-versions.intellijSdk=193.6494.35
+versions.intellijSdk=202.5103-EAP-CANDIDATE-SNAPSHOT
versions.androidBuildTools=r23.0.1
-versions.idea.NodeJS=181.3494.12
-versions.jar.asm-all=7.0.1
-versions.jar.guava=27.1-jre
-versions.jar.groovy-all=2.4.17
+versions.idea.NodeJS=193.6494.7
+versions.jar.asm-all=8.0.1
+versions.jar.guava=29.0-jre
+versions.jar.groovy=2.5.11
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2-2
versions.jar.kxml2=2.3.0
-versions.jar.streamex=0.6.8
-versions.jar.gson=2.8.5
+versions.jar.streamex=0.7.2
+versions.jar.gson=2.8.6
versions.jar.oro=2.0.8
versions.jar.picocontainer=1.2
versions.jar.serviceMessages=2019.1.4
-versions.jar.lz4-java=1.6.0
+versions.jar.lz4-java=1.7.1
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1
versions.shadow=5.2.0
\ No newline at end of file
diff --git a/gradle/versions.properties.193 b/gradle/versions.properties.193
new file mode 100644
index 0000000..0d985de
--- /dev/null
+++ b/gradle/versions.properties.193
@@ -0,0 +1,18 @@
+versions.intellijSdk=193.6494.35
+versions.androidBuildTools=r23.0.1
+versions.idea.NodeJS=181.3494.12
+versions.jar.asm-all=7.0.1
+versions.jar.guava=27.1-jre
+versions.jar.groovy-all=2.4.17
+versions.jar.lombok-ast=0.2.3
+versions.jar.swingx-core=1.6.2-2
+versions.jar.kxml2=2.3.0
+versions.jar.streamex=0.6.8
+versions.jar.gson=2.8.5
+versions.jar.oro=2.0.8
+versions.jar.picocontainer=1.2
+versions.jar.serviceMessages=2019.1.4
+versions.jar.lz4-java=1.6.0
+ignore.jar.snappy-in-java=true
+versions.gradle-api=4.5.1
+versions.shadow=5.2.0
\ No newline at end of file
diff --git a/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt b/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt
index b7670d3..c540056 100644
--- a/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt
+++ b/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.util
-import com.intellij.AbstractBundle
+import com.intellij.DynamicBundle
-abstract class AbstractKotlinBundle protected constructor(pathToBundle: String) : AbstractBundle(pathToBundle) {
+abstract class AbstractKotlinBundle protected constructor(pathToBundle: String) : DynamicBundle(pathToBundle) {
protected fun String.withHtml(): String = "<html>$this</html>"
}
\ No newline at end of file
diff --git a/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt.193 b/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt.193
new file mode 100644
index 0000000..b7670d3
--- /dev/null
+++ b/idea/ide-common/src/org/jetbrains/kotlin/util/AbstractKotlinBundle.kt.193
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.util
+
+import com.intellij.AbstractBundle
+
+abstract class AbstractKotlinBundle protected constructor(pathToBundle: String) : AbstractBundle(pathToBundle) {
+ protected fun String.withHtml(): String = "<html>$this</html>"
+}
\ No newline at end of file
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
index 1b2cf1f..a265dd0 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
@@ -9,6 +9,6 @@
import com.intellij.util.Processor
// FIX ME WHEN BUNCH 193 REMOVED
-typealias StringProcessor = Processor<String>
-typealias PsiMethodProcessor = Processor<PsiMethod>
+typealias StringProcessor = Processor<in String>
+typealias PsiMethodProcessor = Processor<in PsiMethod>
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193
new file mode 100644
index 0000000..1b2cf1f
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.caches
+
+import com.intellij.psi.PsiMethod
+import com.intellij.util.Processor
+
+// FIX ME WHEN BUNCH 193 REMOVED
+typealias StringProcessor = Processor<String>
+typealias PsiMethodProcessor = Processor<PsiMethod>
+
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
index 107e571..cfb3997 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
@@ -8,13 +8,17 @@
import com.intellij.codeInsight.intention.EmptyIntentionAction
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.ProblemHighlightType
-import com.intellij.lang.annotation.Annotation
+import com.intellij.lang.annotation.AnnotationBuilder
import com.intellij.lang.annotation.AnnotationHolder
+import com.intellij.lang.annotation.HighlightSeverity
+import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
import com.intellij.util.containers.MultiMap
+import com.intellij.xml.util.XmlStringUtil
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity
+import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
class AnnotationPresentationInfo(
@@ -28,35 +32,67 @@
for (range in ranges) {
for (diagnostic in diagnostics) {
val fixes = fixesMap[diagnostic]
- val annotation = create(diagnostic, range, holder)
-
- fixes.forEach {
- when (it) {
- is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null)
- is IntentionAction -> annotation.registerFix(it)
+ create(diagnostic, range, holder) { annotation ->
+ fixes.forEach {
+ when (it) {
+ is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix()
+ is IntentionAction -> annotation.newFix(it).registerFix()
+ }
}
- }
- if (diagnostic.severity == Severity.WARNING) {
- annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory)
+ if (diagnostic.severity == Severity.WARNING) {
+ annotation.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory))
- if (fixes.isEmpty()) {
- // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
- annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name))
+ if (fixes.isEmpty()) {
+ // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
+ annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix()
+ }
}
}
}
}
}
- private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation =
- Diagnostic2Annotation.createAnnotation(
- diagnostic,
- range,
- holder,
- nonDefaultMessage,
- textAttributes,
- highlightType,
- IdeErrorMessages::render
- )
+ private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (AnnotationBuilder) -> Unit) {
+ val severity = when (diagnostic.severity) {
+ Severity.ERROR -> HighlightSeverity.ERROR
+ Severity.WARNING -> if (highlightType == ProblemHighlightType.WEAK_WARNING) {
+ HighlightSeverity.WEAK_WARNING
+ } else HighlightSeverity.WARNING
+ Severity.INFO -> HighlightSeverity.WEAK_WARNING
+ }
+
+ holder.newAnnotation(severity, nonDefaultMessage ?: getDefaultMessage(diagnostic))
+ .range(range)
+ .tooltip(getMessage(diagnostic))
+ .also { builder -> highlightType?.let { builder.highlightType(it) } }
+ .also { builder -> textAttributes?.let { builder.textAttributes(it) } }
+ .also { consumer(it) }
+ .create()
+ }
+
+ private fun getMessage(diagnostic: Diagnostic): String {
+ var message = IdeErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ val factoryName = diagnostic.factory.name
+ message = if (message.startsWith("<html>")) {
+ "<html>[$factoryName] ${message.substring("<html>".length)}"
+ } else {
+ "[$factoryName] $message"
+ }
+ }
+ if (!message.startsWith("<html>")) {
+ message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
+ }
+ return message
+ }
+
+ private fun getDefaultMessage(diagnostic: Diagnostic): String {
+ val message = DefaultErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ return "[${diagnostic.factory.name}] $message"
+ }
+ return message
+ }
+
}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193
new file mode 100644
index 0000000..107e571
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter
+
+import com.intellij.codeInsight.intention.EmptyIntentionAction
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.lang.annotation.Annotation
+import com.intellij.lang.annotation.AnnotationHolder
+import com.intellij.openapi.editor.colors.TextAttributesKey
+import com.intellij.openapi.util.TextRange
+import com.intellij.util.containers.MultiMap
+import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.diagnostics.Severity
+import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
+
+class AnnotationPresentationInfo(
+ val ranges: List<TextRange>,
+ val nonDefaultMessage: String? = null,
+ val highlightType: ProblemHighlightType? = null,
+ val textAttributes: TextAttributesKey? = null
+) {
+
+ fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
+ for (range in ranges) {
+ for (diagnostic in diagnostics) {
+ val fixes = fixesMap[diagnostic]
+ val annotation = create(diagnostic, range, holder)
+
+ fixes.forEach {
+ when (it) {
+ is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null)
+ is IntentionAction -> annotation.registerFix(it)
+ }
+ }
+
+ if (diagnostic.severity == Severity.WARNING) {
+ annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory)
+
+ if (fixes.isEmpty()) {
+ // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
+ annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name))
+ }
+ }
+ }
+ }
+ }
+
+ private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation =
+ Diagnostic2Annotation.createAnnotation(
+ diagnostic,
+ range,
+ holder,
+ nonDefaultMessage,
+ textAttributes,
+ highlightType,
+ IdeErrorMessages::render
+ )
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
index 053f070..0d3c844 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
@@ -64,7 +64,7 @@
}
}
else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
- return LightJavaModule.getModule(PsiManager.getInstance(project), root);
+ return LightJavaModule.findModule(PsiManager.getInstance(project), root);
}
}
else if ((root = index.getSourceRootForFile(file)) != null) {
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193
new file mode 100644
index 0000000..053f070
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193
@@ -0,0 +1,114 @@
+/*
+ * 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.modules;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.PsiJavaModule;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.impl.light.LightJavaModule;
+import kotlin.collections.ArraysKt;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
+
+// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil
+public class ModuleHighlightUtil2 {
+ private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release");
+
+ @Nullable
+ static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) {
+ ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
+ if (index.isInLibrary(file)) {
+ VirtualFile root;
+ if ((root = index.getClassRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (descriptorFile == null) {
+ VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (alt != null && isMultiReleaseJar(root)) {
+ descriptorFile = alt;
+ }
+ }
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
+ return LightJavaModule.getModule(PsiManager.getInstance(project), root);
+ }
+ }
+ else if ((root = index.getSourceRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE);
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+ else {
+ Module module = index.getModuleForFile(file);
+ if (module != null) {
+ boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file);
+ VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest),
+ root -> root.findChild(MODULE_INFO_FILE) != null);
+ if (modularRoot != null) {
+ VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE);
+ assert moduleInfo != null : modularRoot;
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isMultiReleaseJar(VirtualFile root) {
+ if (root.getFileSystem() instanceof JarFileSystem) {
+ VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME);
+ if (manifest != null) {
+ try (InputStream stream = manifest.getInputStream()) {
+ return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE));
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt
index 4a72c82..65c7352 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt
@@ -6,12 +6,9 @@
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.ide.highlighter.JavaFileType
+import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
-import com.intellij.psi.impl.cache.CacheManager
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.search.ScopeOptimizer
-import com.intellij.psi.search.SearchScope
-import com.intellij.psi.search.UsageSearchContext
+import com.intellij.psi.search.*
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.search.excludeFileTypes
@@ -31,19 +28,22 @@
val file = callable.parent as KtFile
val packageName = file.packageFqName.takeUnless { it.isRoot } ?: return null
val project = file.project
- val cacheManager = CacheManager.SERVICE.getInstance(project)
+ val searchHelper = PsiSearchHelper.getInstance(project)
val kotlinScope = GlobalSearchScope.getScopeRestrictedByFileTypes(useScope, KotlinFileType.INSTANCE)
val javaScope = GlobalSearchScope.getScopeRestrictedByFileTypes(useScope, JavaFileType.INSTANCE)
val restScope = useScope.excludeFileTypes(KotlinFileType.INSTANCE, JavaFileType.INSTANCE) as GlobalSearchScope
- //TODO: use all components of package name?
- val shortPackageName = packageName.shortName().identifier
- val kotlinFiles = cacheManager.getVirtualFilesWithWord(shortPackageName, UsageSearchContext.IN_CODE, kotlinScope, true)
+ val kotlinFiles = mutableListOf<VirtualFile>()
+ searchHelper.processCandidateFilesForText(kotlinScope, UsageSearchContext.IN_CODE, true, packageName.asString()) {
+ kotlinFiles.add(it)
+ }
- val javaFacadeName = file.javaFileFacadeFqName.shortName().identifier
- val javaFiles = cacheManager.getVirtualFilesWithWord(javaFacadeName, UsageSearchContext.IN_CODE, javaScope, true)
+ val javaFiles = mutableListOf<VirtualFile>()
+ searchHelper.processCandidateFilesForText(javaScope, UsageSearchContext.IN_CODE, true, file.javaFileFacadeFqName.asString()) {
+ javaFiles.add(it)
+ }
- return GlobalSearchScope.filesScope(project, (kotlinFiles + javaFiles).asList()).uniteWith(restScope)
+ return GlobalSearchScope.filesScope(project, kotlinFiles + javaFiles).uniteWith(restScope)
}
}
\ No newline at end of file
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt.193
new file mode 100644
index 0000000..4a72c82
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferenceScopeOptimizer.kt.193
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.search.ideaExtensions
+
+import com.intellij.ide.highlighter.JavaFileType
+import com.intellij.psi.PsiElement
+import com.intellij.psi.impl.cache.CacheManager
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.search.ScopeOptimizer
+import com.intellij.psi.search.SearchScope
+import com.intellij.psi.search.UsageSearchContext
+import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.search.excludeFileTypes
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtFile
+
+class KotlinReferenceScopeOptimizer : ScopeOptimizer {
+ override fun getRestrictedUseScope(element: PsiElement): SearchScope? {
+ if (element is KtCallableDeclaration && element.parent is KtFile) {
+ return getRestrictedScopeForTopLevelCallable(element)
+ }
+ return null
+ }
+
+ private fun getRestrictedScopeForTopLevelCallable(callable: KtCallableDeclaration): GlobalSearchScope? {
+ val useScope = callable.useScope as? GlobalSearchScope ?: return null
+ val file = callable.parent as KtFile
+ val packageName = file.packageFqName.takeUnless { it.isRoot } ?: return null
+ val project = file.project
+ val cacheManager = CacheManager.SERVICE.getInstance(project)
+
+ val kotlinScope = GlobalSearchScope.getScopeRestrictedByFileTypes(useScope, KotlinFileType.INSTANCE)
+ val javaScope = GlobalSearchScope.getScopeRestrictedByFileTypes(useScope, JavaFileType.INSTANCE)
+ val restScope = useScope.excludeFileTypes(KotlinFileType.INSTANCE, JavaFileType.INSTANCE) as GlobalSearchScope
+
+ //TODO: use all components of package name?
+ val shortPackageName = packageName.shortName().identifier
+ val kotlinFiles = cacheManager.getVirtualFilesWithWord(shortPackageName, UsageSearchContext.IN_CODE, kotlinScope, true)
+
+ val javaFacadeName = file.javaFileFacadeFqName.shortName().identifier
+ val javaFiles = cacheManager.getVirtualFilesWithWord(javaFacadeName, UsageSearchContext.IN_CODE, javaScope, true)
+
+ return GlobalSearchScope.filesScope(project, (kotlinFiles + javaFiles).asList()).uniteWith(restScope)
+ }
+}
\ No newline at end of file
diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
index fdd15cc..b40f014 100644
--- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
+++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
@@ -5,9 +5,10 @@
package org.jetbrains.kotlin.idea.completion.test.handlers
+import com.intellij.codeInsight.lookup.LookupFocusDegree
import com.intellij.codeInsight.lookup.impl.LookupImpl
// FIX ME WHEN BUNCH 193 REMOVED
fun LookupImpl.setFocusedFocusDegree() {
- focusDegree = LookupImpl.FocusDegree.FOCUSED
+ this.lookupFocusDegree = LookupFocusDegree.FOCUSED
}
\ No newline at end of file
diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193 b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193
new file mode 100644
index 0000000..fdd15cc
--- /dev/null
+++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.completion.test.handlers
+
+import com.intellij.codeInsight.lookup.impl.LookupImpl
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun LookupImpl.setFocusedFocusDegree() {
+ focusDegree = LookupImpl.FocusDegree.FOCUSED
+}
\ No newline at end of file
diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt
index 49e33e2..6a49adb 100644
--- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt
+++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt
@@ -1,28 +1,27 @@
/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-
package org.jetbrains.kotlin.idea.caches.trackers
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.SimpleModificationTracker
import com.intellij.pom.tree.TreeAspect
+import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.idea.util.application.getServiceSafe
+import org.jetbrains.kotlin.psi.KtFile
/**
* Tested in OutOfBlockModificationTestGenerated
*/
// FIX ME WHEN BUNCH 193 REMOVED
-class KotlinCodeBlockModificationListener(
- project: Project,
- treeAspect: TreeAspect
-) : KotlinCodeBlockModificationListenerCompat(project) {
+class KotlinCodeBlockModificationListener(project: Project) : KotlinCodeBlockModificationListenerCompat(project) {
init {
init(
- treeAspect,
+ TreeAspect.getInstance(project),
incOCBCounter = { ktFile ->
kotlinOutOfCodeBlockTrackerImpl.incModificationCount()
perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true)
@@ -31,7 +30,6 @@
SimpleModificationTracker()
},
psiModificationTrackerListener = {
- @Suppress("UnstableApiUsage")
val kotlinTrackerInternalIDECount =
modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount
if (kotlinModificationTracker == kotlinTrackerInternalIDECount) {
@@ -47,7 +45,6 @@
}
companion object {
- fun getInstance(project: Project): KotlinCodeBlockModificationListener =
- project.getComponent(KotlinCodeBlockModificationListener::class.java)
+ fun getInstance(project: Project): KotlinCodeBlockModificationListener = project.getServiceSafe()
}
-}
+}
\ No newline at end of file
diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.193 b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.193
new file mode 100644
index 0000000..49e33e2
--- /dev/null
+++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.193
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+
+package org.jetbrains.kotlin.idea.caches.trackers
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.SimpleModificationTracker
+import com.intellij.pom.tree.TreeAspect
+import org.jetbrains.kotlin.idea.KotlinLanguage
+
+/**
+ * Tested in OutOfBlockModificationTestGenerated
+ */
+// FIX ME WHEN BUNCH 193 REMOVED
+class KotlinCodeBlockModificationListener(
+ project: Project,
+ treeAspect: TreeAspect
+) : KotlinCodeBlockModificationListenerCompat(project) {
+
+ init {
+ init(
+ treeAspect,
+ incOCBCounter = { ktFile ->
+ kotlinOutOfCodeBlockTrackerImpl.incModificationCount()
+ perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true)
+ },
+ kotlinOutOfCodeBlockTrackerProducer = {
+ SimpleModificationTracker()
+ },
+ psiModificationTrackerListener = {
+ @Suppress("UnstableApiUsage")
+ val kotlinTrackerInternalIDECount =
+ modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount
+ if (kotlinModificationTracker == kotlinTrackerInternalIDECount) {
+ // Some update that we are not sure is from Kotlin language, as Kotlin language tracker wasn't changed
+ kotlinOutOfCodeBlockTrackerImpl.incModificationCount()
+ } else {
+ kotlinModificationTracker = kotlinTrackerInternalIDECount
+ }
+
+ perModuleOutOfCodeBlockTrackerUpdater.onPsiModificationTrackerUpdate()
+ }
+ )
+ }
+
+ companion object {
+ fun getInstance(project: Project): KotlinCodeBlockModificationListener =
+ project.getComponent(KotlinCodeBlockModificationListener::class.java)
+ }
+}
diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
index de74378..a6b3880 100644
--- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
+++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
@@ -1,6 +1,17 @@
/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ * 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.util.application
@@ -8,8 +19,8 @@
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.components.ComponentManager
+import com.intellij.openapi.progress.impl.CancellationCheck
import com.intellij.openapi.project.Project
-import org.jetbrains.annotations.Nls
fun <T> runReadAction(action: () -> T): T {
return ApplicationManager.getApplication().runReadAction<T>(action)
@@ -19,22 +30,22 @@
return ApplicationManager.getApplication().runWriteAction<T>(action)
}
-fun Project.executeWriteCommand(@Nls name: String, command: () -> Unit) {
+fun Project.executeWriteCommand(name: String, command: () -> Unit) {
CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
}
-fun <T> Project.executeWriteCommand(@Nls name: String, groupId: Any? = null, command: () -> T): T {
+fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
return executeCommand<T>(name, groupId) { runWriteAction(command) }
}
-fun <T> Project.executeCommand(@Nls name: String, groupId: Any? = null, command: () -> T): T {
+fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
@Suppress("UNCHECKED_CAST") var result: T = null as T
CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
@Suppress("USELESS_CAST")
return result as T
}
-fun <T> runWithCancellationCheck(block: () -> T): T = block()
+fun <T> runWithCancellationCheck(block: () -> T): T = CancellationCheck.runWithCancellationCheck(block)
inline fun executeOnPooledThread(crossinline action: () -> Unit) =
ApplicationManager.getApplication().executeOnPooledThread { action() }
diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193 b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193
new file mode 100644
index 0000000..de74378
--- /dev/null
+++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.util.application
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.command.CommandProcessor
+import com.intellij.openapi.components.ComponentManager
+import com.intellij.openapi.project.Project
+import org.jetbrains.annotations.Nls
+
+fun <T> runReadAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runReadAction<T>(action)
+}
+
+fun <T> runWriteAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runWriteAction<T>(action)
+}
+
+fun Project.executeWriteCommand(@Nls name: String, command: () -> Unit) {
+ CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
+}
+
+fun <T> Project.executeWriteCommand(@Nls name: String, groupId: Any? = null, command: () -> T): T {
+ return executeCommand<T>(name, groupId) { runWriteAction(command) }
+}
+
+fun <T> Project.executeCommand(@Nls name: String, groupId: Any? = null, command: () -> T): T {
+ @Suppress("UNCHECKED_CAST") var result: T = null as T
+ CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
+ @Suppress("USELESS_CAST")
+ return result as T
+}
+
+fun <T> runWithCancellationCheck(block: () -> T): T = block()
+
+inline fun executeOnPooledThread(crossinline action: () -> Unit) =
+ ApplicationManager.getApplication().executeOnPooledThread { action() }
+
+inline fun invokeLater(crossinline action: () -> Unit) =
+ ApplicationManager.getApplication().invokeLater { action() }
+
+inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUnitTestMode
+
+inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
+ this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorPosition.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorPosition.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorPosition.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorPosition.java.193
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReport.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReport.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReport.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReport.java.193
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReportSeverity.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReportSeverity.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReportSeverity.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/EditorReportSeverity.java.193
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslModelsParameters.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslModelsParameters.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslModelsParameters.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslModelsParameters.java.193
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptModel.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptModel.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptModel.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptModel.java.193
diff --git a/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptsModel.java b/idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptsModel.java.193
similarity index 100%
rename from idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptsModel.java
rename to idea/idea-gradle-tooling-api/src/org/gradle/tooling/model/kotlin/dsl/KotlinDslScriptsModel.java.193
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt
index b103d5e..1451b36 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt
@@ -45,7 +45,7 @@
RevealFileAction.openDirectory(logsDir)
} else {
val parent = WindowManager.getInstance().getStatusBar(project)?.component
- ?: WindowManager.getInstance().findVisibleFrame().rootPane
+ ?: WindowManager.getInstance().findVisibleFrame()?.rootPane
JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder(
KotlinIdeaGradleBundle.message(
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt.193
new file mode 100644
index 0000000..b103d5e
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt.193
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.actions
+
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.ide.actions.RevealFileAction
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.MessageType
+import com.intellij.openapi.ui.popup.JBPopupFactory
+import com.intellij.openapi.util.SystemInfo
+import com.intellij.openapi.wm.WindowManager
+import com.intellij.psi.PsiFile
+import com.intellij.ui.BrowserHyperlinkListener
+import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
+import java.io.File
+
+class ShowKotlinGradleDslLogs : IntentionAction, AnAction(), DumbAware {
+ override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
+ openLogsDirIfPresent(project)
+ }
+
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ openLogsDirIfPresent(project)
+ }
+
+ override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = RevealFileAction.isSupported()
+
+ override fun update(e: AnActionEvent) {
+ val presentation = e.presentation
+ presentation.isEnabledAndVisible = e.project != null && RevealFileAction.isSupported()
+ presentation.text = NAME
+ }
+
+ private fun openLogsDirIfPresent(project: Project) {
+ val logsDir = findLogsDir()
+ if (logsDir != null) {
+ RevealFileAction.openDirectory(logsDir)
+ } else {
+ val parent = WindowManager.getInstance().getStatusBar(project)?.component
+ ?: WindowManager.getInstance().findVisibleFrame().rootPane
+ JBPopupFactory.getInstance()
+ .createHtmlTextBalloonBuilder(
+ KotlinIdeaGradleBundle.message(
+ "text.gradle.dsl.logs.cannot.be.found.automatically.see.how.to.find.logs",
+ gradleTroubleshootingLink
+ ),
+ MessageType.ERROR,
+ BrowserHyperlinkListener.INSTANCE
+ )
+ .setFadeoutTime(5000)
+ .createBalloon()
+ .showInCenterOf(parent)
+ }
+ }
+
+ /** The way how to find Gradle logs is described here
+ * @see org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs.gradleTroubleshootingLink
+ */
+ private fun findLogsDir(): File? {
+ val userHome = System.getProperty("user.home")
+ return when {
+ SystemInfo.isMac -> File("$userHome/Library/Logs/gradle-kotlin-dsl")
+ SystemInfo.isLinux -> File("$userHome/.gradle-kotlin-dsl/logs")
+ SystemInfo.isWindows -> File("$userHome/AppData/Local/gradle-kotlin-dsl/log")
+ else -> null
+ }.takeIf { it?.exists() == true }
+ }
+
+ override fun startInWriteAction() = false
+
+ override fun getText() = NAME
+
+ override fun getFamilyName() = NAME
+
+ companion object {
+ private const val gradleTroubleshootingLink = "https://docs.gradle.org/current/userguide/kotlin_dsl.html#troubleshooting"
+
+ val NAME = KotlinIdeaGradleBundle.message("action.text.show.kotlin.gradle.dsl.logs.in", RevealFileAction.getFileManagerName())
+ }
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
index ec55659..dff12e1 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
@@ -13,8 +13,8 @@
// FIX ME WHEN BUNCH 193 REMOVED
abstract class AbstractProjectResolverExtensionCompat : AbstractProjectResolverExtension() {
- override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
- return super.createModule(gradleModule, projectDataNode).also {
+ override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData>? {
+ return super.createModule(gradleModule, projectDataNode)?.also {
initializeModuleNode(gradleModule, it, projectDataNode)
}
}
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193
new file mode 100644
index 0000000..ec55659
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.intellij.openapi.externalSystem.model.DataNode
+import com.intellij.openapi.externalSystem.model.project.ModuleData
+import com.intellij.openapi.externalSystem.model.project.ProjectData
+import org.gradle.tooling.model.idea.IdeaModule
+import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
+
+// FIX ME WHEN BUNCH 193 REMOVED
+abstract class AbstractProjectResolverExtensionCompat : AbstractProjectResolverExtension() {
+ override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
+ return super.createModule(gradleModule, projectDataNode).also {
+ initializeModuleNode(gradleModule, it, projectDataNode)
+ }
+ }
+
+ // Inline after class remove
+ abstract fun initializeModuleNode(
+ gradleModule: IdeaModule,
+ moduleDataNode: DataNode<ModuleData>,
+ projectDataNode: DataNode<ProjectData>,
+ )
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinNonJvmGutterConfigurator.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinNonJvmGutterConfigurator.kt.193
similarity index 100%
rename from idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinNonJvmGutterConfigurator.kt
rename to idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinNonJvmGutterConfigurator.kt.193
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
index ccc50c9..77ed5aa 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
@@ -5,7 +5,8 @@
package org.jetbrains.kotlin.idea.scripting.gradle
-import com.intellij.openapi.externalSystem.service.project.autoimport.AsyncFileChangeListenerBase
+import com.intellij.openapi.externalSystem.autoimport.AsyncFileChangeListenerBase
+import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
@@ -17,19 +18,27 @@
) {
VirtualFileManager.getInstance().addAsyncFileListener(
object : AsyncFileChangeListenerBase() {
+ val changedFiles = mutableListOf<String>()
+
+ override fun init() {
+ changedFiles.clear()
+ }
+
override fun isRelevant(path: String): Boolean {
return buildRootsManager.maybeAffectedGradleProjectFile(path)
}
override fun updateFile(file: VirtualFile, event: VFileEvent) {
- watcher.fileChanged(event.path, file.timeStamp)
+ changedFiles.add(event.path)
}
- // do nothing
- override fun prepareFileDeletion(file: VirtualFile) {}
- override fun apply() {}
- override fun reset() {}
-
+ override fun apply() {
+ changedFiles.forEach {
+ LocalFileSystem.getInstance().findFileByPath(it)?.let { f ->
+ watcher.fileChanged(f.path, f.timeStamp)
+ }
+ }
+ }
},
watcher.project
)
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193
new file mode 100644
index 0000000..ccc50c9
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scripting.gradle
+
+import com.intellij.openapi.externalSystem.service.project.autoimport.AsyncFileChangeListenerBase
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.vfs.newvfs.events.VFileEvent
+import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
+
+fun addVfsListener(
+ watcher: GradleScriptListener,
+ buildRootsManager: GradleBuildRootsManager
+) {
+ VirtualFileManager.getInstance().addAsyncFileListener(
+ object : AsyncFileChangeListenerBase() {
+ override fun isRelevant(path: String): Boolean {
+ return buildRootsManager.maybeAffectedGradleProjectFile(path)
+ }
+
+ override fun updateFile(file: VirtualFile, event: VFileEvent) {
+ watcher.fileChanged(event.path, file.timeStamp)
+ }
+
+ // do nothing
+ override fun prepareFileDeletion(file: VirtualFile) {}
+ override fun apply() {}
+ override fun reset() {}
+
+ },
+ watcher.project
+ )
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt
index 472e342..a26d34d 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt
@@ -7,31 +7,32 @@
package org.jetbrains.kotlin.idea.scripting.gradle
-import com.intellij.notification.*
+import com.intellij.diff.util.DiffUtil
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.ServiceManager
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.editor.Editor
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
-import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
+import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Key
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
-import org.gradle.util.GradleVersion
+import com.intellij.testFramework.LightVirtualFileBase
+import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
+import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
+import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
-import org.jetbrains.kotlin.idea.util.application.getServiceSafe
-import org.jetbrains.kotlin.psi.UserDataProperty
-import org.jetbrains.plugins.gradle.service.GradleInstallationManager
+import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
+import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
val scriptConfigurationsNeedToBeUpdatedBalloon
- get() = Registry.`is`("kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedBalloon", false)
+ get() = Registry.`is`("kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedFloatingNotification", true)
fun runPartialGradleImportForAllRoots(project: Project) {
GradleBuildRootsManager.getInstance(project).getAllRoots().forEach { root ->
@@ -45,97 +46,83 @@
ExternalSystemUtil.refreshProject(
root.pathPrefix,
ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
- .build()
+ .projectResolverPolicy(
+ GradlePartialResolverPolicy { it is KotlinDslScriptModelResolver }
+ )
)
}
-fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.label.import.project")
+fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.text.load.script.configurations")
-fun autoReloadScriptConfigurations(project: Project, root: GradleBuildRoot): Boolean {
- return ExternalSystemApiUtil
- .getSettings(project, GradleConstants.SYSTEM_ID)
- .getLinkedProjectSettings(root.pathPrefix)
- ?.isUseAutoImport ?: false
+fun autoReloadScriptConfigurations(project: Project, file: VirtualFile): Boolean {
+ val definition = file.findScriptDefinition(project) ?: return false
+
+ return KotlinScriptingSettings.getInstance(project).autoReloadConfigurations(definition)
}
-private const val kotlinDslNotificationGroupId = "Gradle Kotlin DSL Scripts"
-private var Project.notificationPanel: ScriptConfigurationChangedNotification?
- by UserDataProperty<Project, ScriptConfigurationChangedNotification>(Key.create("load.script.configuration.panel"))
-
fun scriptConfigurationsNeedToBeUpdated(project: Project, file: VirtualFile) {
- if (!scriptConfigurationsNeedToBeUpdatedBalloon) return
-
- val root = GradleBuildRootsManager.getInstance(project).getScriptInfo(file)?.buildRoot ?: return
- if (autoReloadScriptConfigurations(project, root)) {
- // import should be run automatically by Gradle plugin
- return
- }
-
- val existingPanel = project.notificationPanel
- if (existingPanel != null) {
- return
- }
-
- val notificationGroup = NotificationGroup.findRegisteredGroup(kotlinDslNotificationGroupId)
- if (notificationGroup == null) {
- NotificationsConfiguration.getNotificationsConfiguration().register(
- kotlinDslNotificationGroupId, NotificationDisplayType.STICKY_BALLOON, false
- )
- }
-
- val notification = ScriptConfigurationChangedNotification(project)
- project.notificationPanel = notification
- notification.notify(project)
-}
-
-fun scriptConfigurationsAreUpToDate(project: Project): Boolean {
- if (project.notificationPanel == null) return false
- project.notificationPanel?.expire()
- return true
-}
-
-private class ScriptConfigurationChangedNotification(val project: Project) :
- Notification(
- kotlinDslNotificationGroupId,
- KotlinIcons.LOAD_SCRIPT_CONFIGURATION,
- KotlinIdeaGradleBundle.message("notification.title.script.configuration.has.been.changed"),
- null,
- KotlinIdeaGradleBundle.message("notification.text.script.configuration.has.been.changed"),
- NotificationType.INFORMATION,
- null
- ) {
-
- init {
- addAction(LoadConfigurationAction())
- addAction(NotificationAction.createSimple(KotlinIdeaGradleBundle.message("action.label.enable.auto.import")) {
- GradleBuildRootsManager.getInstance(project).getAllRoots().forEach { root ->
- val projectSettings = getGradleProjectSettings(project).find { it.externalProjectPath == root.pathPrefix }
- if (projectSettings != null) {
- projectSettings.isUseAutoImport = true
- }
- runPartialGradleImport(project, root)
- }
- })
- }
-
- override fun expire() {
- super.expire()
-
- project.notificationPanel = null
- }
-
- private class LoadConfigurationAction : AnAction(KotlinIdeaGradleBundle.message("action.label.import.project")) {
- override fun actionPerformed(e: AnActionEvent) {
- val project = e.project ?: return
- runPartialGradleImportForAllRoots(project)
+ if (autoReloadScriptConfigurations(project, file)) {
+ GradleBuildRootsManager.getInstance(project).getScriptInfo(file)?.buildRoot?.let {
+ runPartialGradleImport(project, it)
}
+ } else {
+ // notification is shown in LoadConfigurationAction
+ }
+}
+
+fun scriptConfigurationsAreUpToDate(project: Project): Boolean = true
+
+class LoadConfigurationAction : AnAction(
+ KotlinIdeaGradleBundle.message("action.text.load.script.configurations"),
+ KotlinIdeaGradleBundle.message("action.description.load.script.configurations"),
+ KotlinIcons.LOAD_SCRIPT_CONFIGURATION
+) {
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ val editor = e.getData(CommonDataKeys.EDITOR) ?: return
+ val file = getKotlinScriptFile(editor) ?: return
+ val root = GradleBuildRootsManager.getInstance(project).getScriptInfo(file)?.buildRoot ?: return
+
+ runPartialGradleImport(project, root)
+ }
+
+ override fun update(e: AnActionEvent) {
+ ensureValidActionVisibility(e)
+ }
+
+ private fun ensureValidActionVisibility(e: AnActionEvent) {
+ val editor = e.getData(CommonDataKeys.EDITOR) ?: return
+
+ e.presentation.isVisible = getNotificationVisibility(editor)
+ }
+
+ private fun getNotificationVisibility(editor: Editor): Boolean {
+ if (!scriptConfigurationsNeedToBeUpdatedBalloon) return false
+
+ if (DiffUtil.isDiffEditor(editor)) return false
+
+ val project = editor.project ?: return false
+ val file = getKotlinScriptFile(editor) ?: return false
+
+ if (autoReloadScriptConfigurations(project, file)) {
+ return false
+ }
+
+ return GradleBuildRootsManager.getInstance(project).isConfigurationOutOfDate(file)
+ }
+
+ private fun getKotlinScriptFile(editor: Editor): VirtualFile? {
+ return FileDocumentManager.getInstance()
+ .getFile(editor.document)
+ ?.takeIf {
+ it !is LightVirtualFileBase
+ && it.isValid
+ && it.fileType == KotlinFileType.INSTANCE
+ && isGradleKotlinScript(it)
+ }
}
}
fun getGradleVersion(project: Project, settings: GradleProjectSettings): String {
- // workaround for bug in settings.resolveGradleVersion().version (fixed in 201)
- return GradleInstallationManager.getGradleVersion(
- ServiceManager.getService(GradleInstallationManager::class.java)
- .getGradleHome(project, settings.externalProjectPath)?.path
- ) ?: GradleVersion.current().version
+ return settings.resolveGradleVersion().version
}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.193
new file mode 100644
index 0000000..472e342
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.193
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package org.jetbrains.kotlin.idea.scripting.gradle
+
+import com.intellij.notification.*
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.components.ServiceManager
+import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Key
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.openapi.vfs.VirtualFile
+import org.gradle.util.GradleVersion
+import org.jetbrains.kotlin.idea.KotlinIcons
+import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
+import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot
+import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
+import org.jetbrains.kotlin.idea.util.application.getServiceSafe
+import org.jetbrains.kotlin.psi.UserDataProperty
+import org.jetbrains.plugins.gradle.service.GradleInstallationManager
+import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
+import org.jetbrains.plugins.gradle.util.GradleConstants
+
+val scriptConfigurationsNeedToBeUpdatedBalloon
+ get() = Registry.`is`("kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedBalloon", false)
+
+fun runPartialGradleImportForAllRoots(project: Project) {
+ GradleBuildRootsManager.getInstance(project).getAllRoots().forEach { root ->
+ runPartialGradleImport(project, root)
+ }
+}
+
+fun runPartialGradleImport(project: Project, root: GradleBuildRoot) {
+ if (root.isImportingInProgress()) return
+
+ ExternalSystemUtil.refreshProject(
+ root.pathPrefix,
+ ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
+ .build()
+ )
+}
+
+fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.label.import.project")
+
+fun autoReloadScriptConfigurations(project: Project, root: GradleBuildRoot): Boolean {
+ return ExternalSystemApiUtil
+ .getSettings(project, GradleConstants.SYSTEM_ID)
+ .getLinkedProjectSettings(root.pathPrefix)
+ ?.isUseAutoImport ?: false
+}
+
+private const val kotlinDslNotificationGroupId = "Gradle Kotlin DSL Scripts"
+private var Project.notificationPanel: ScriptConfigurationChangedNotification?
+ by UserDataProperty<Project, ScriptConfigurationChangedNotification>(Key.create("load.script.configuration.panel"))
+
+fun scriptConfigurationsNeedToBeUpdated(project: Project, file: VirtualFile) {
+ if (!scriptConfigurationsNeedToBeUpdatedBalloon) return
+
+ val root = GradleBuildRootsManager.getInstance(project).getScriptInfo(file)?.buildRoot ?: return
+ if (autoReloadScriptConfigurations(project, root)) {
+ // import should be run automatically by Gradle plugin
+ return
+ }
+
+ val existingPanel = project.notificationPanel
+ if (existingPanel != null) {
+ return
+ }
+
+ val notificationGroup = NotificationGroup.findRegisteredGroup(kotlinDslNotificationGroupId)
+ if (notificationGroup == null) {
+ NotificationsConfiguration.getNotificationsConfiguration().register(
+ kotlinDslNotificationGroupId, NotificationDisplayType.STICKY_BALLOON, false
+ )
+ }
+
+ val notification = ScriptConfigurationChangedNotification(project)
+ project.notificationPanel = notification
+ notification.notify(project)
+}
+
+fun scriptConfigurationsAreUpToDate(project: Project): Boolean {
+ if (project.notificationPanel == null) return false
+ project.notificationPanel?.expire()
+ return true
+}
+
+private class ScriptConfigurationChangedNotification(val project: Project) :
+ Notification(
+ kotlinDslNotificationGroupId,
+ KotlinIcons.LOAD_SCRIPT_CONFIGURATION,
+ KotlinIdeaGradleBundle.message("notification.title.script.configuration.has.been.changed"),
+ null,
+ KotlinIdeaGradleBundle.message("notification.text.script.configuration.has.been.changed"),
+ NotificationType.INFORMATION,
+ null
+ ) {
+
+ init {
+ addAction(LoadConfigurationAction())
+ addAction(NotificationAction.createSimple(KotlinIdeaGradleBundle.message("action.label.enable.auto.import")) {
+ GradleBuildRootsManager.getInstance(project).getAllRoots().forEach { root ->
+ val projectSettings = getGradleProjectSettings(project).find { it.externalProjectPath == root.pathPrefix }
+ if (projectSettings != null) {
+ projectSettings.isUseAutoImport = true
+ }
+ runPartialGradleImport(project, root)
+ }
+ })
+ }
+
+ override fun expire() {
+ super.expire()
+
+ project.notificationPanel = null
+ }
+
+ private class LoadConfigurationAction : AnAction(KotlinIdeaGradleBundle.message("action.label.import.project")) {
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ runPartialGradleImportForAllRoots(project)
+ }
+ }
+}
+
+fun getGradleVersion(project: Project, settings: GradleProjectSettings): String {
+ // workaround for bug in settings.resolveGradleVersion().version (fixed in 201)
+ return GradleInstallationManager.getGradleVersion(
+ ServiceManager.getService(GradleInstallationManager::class.java)
+ .getGradleHome(project, settings.externalProjectPath)?.path
+ ) ?: GradleVersion.current().version
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt
index fe57d04..04c0961 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt
@@ -10,6 +10,7 @@
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
+import kotlin.script.experimental.location.ScriptExpectedLocation
class GradleKotlinScriptDefinitionWrapper(
hostConfiguration: ScriptingHostConfiguration,
@@ -25,6 +26,5 @@
}
}
- override val canAutoReloadScriptConfigurationsBeSwitchedOff = !kotlinDslScriptsModelImportSupported(gradleVersion)
override val canDefinitionBeSwitchedOff: Boolean = false
}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt.193
new file mode 100644
index 0000000..fe57d04
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptDefinitionWrapper.kt.193
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scripting.gradle
+
+import org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition
+import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
+import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
+import kotlin.script.experimental.api.*
+import kotlin.script.experimental.host.ScriptingHostConfiguration
+
+class GradleKotlinScriptDefinitionWrapper(
+ hostConfiguration: ScriptingHostConfiguration,
+ legacyDefinition: KotlinScriptDefinitionFromAnnotatedTemplate,
+ gradleVersion: String,
+) : ScriptDefinition.FromLegacy(hostConfiguration, legacyDefinition) {
+ override val compilationConfiguration by lazy {
+ ScriptCompilationConfigurationFromDefinition(
+ hostConfiguration,
+ legacyDefinition
+ ).with {
+ ScriptCompilationConfiguration.ide.acceptedLocations.put(listOf(ScriptAcceptedLocation.Project))
+ }
+ }
+
+ override val canAutoReloadScriptConfigurationsBeSwitchedOff = !kotlinDslScriptsModelImportSupported(gradleVersion)
+ override val canDefinitionBeSwitchedOff: Boolean = false
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt
index eb3bb6e..1dad8d7 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt
@@ -5,16 +5,16 @@
package org.jetbrains.kotlin.idea.scripting.gradle.importing
-import com.intellij.openapi.externalSystem.model.DataNode
-import com.intellij.openapi.externalSystem.model.project.ProjectData
-import org.gradle.tooling.model.idea.IdeaProject
import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
import org.jetbrains.kotlin.gradle.KotlinDslScriptAdditionalTask
import org.jetbrains.kotlin.gradle.KotlinDslScriptModelProvider
import org.jetbrains.kotlin.idea.scripting.gradle.kotlinDslScriptsModelImportSupported
-import org.jetbrains.plugins.gradle.model.Build
import org.jetbrains.plugins.gradle.model.ClassSetImportModelProvider
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
+import org.jetbrains.plugins.gradle.service.project.ModifiableGradleProjectModel
+import org.jetbrains.plugins.gradle.service.project.ProjectModelContributor
+import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
+import org.jetbrains.plugins.gradle.service.project.ToolingModelsProvider
class KotlinDslScriptModelResolver : KotlinDslScriptModelResolverCommon() {
override fun requiresTaskRunning() = true
@@ -27,26 +27,22 @@
setOf(KotlinDslScriptAdditionalTask::class.java)
)
}
+}
- override fun populateProjectExtraModels(gradleProject: IdeaProject, ideProject: DataNode<ProjectData>) {
- super.populateProjectExtraModels(gradleProject, ideProject)
-
- populateBuildModels(resolverCtx.models.mainBuild, ideProject)
-
- resolverCtx.models.includedBuilds.forEach { includedRoot ->
- populateBuildModels(includedRoot, ideProject)
- }
- }
-
- private fun populateBuildModels(
- root: Build,
- ideProject: DataNode<ProjectData>
+@Suppress("UnstableApiUsage")
+class KotlinDslScriptModelContributor : ProjectModelContributor {
+ override fun accept(
+ projectModelBuilder: ModifiableGradleProjectModel,
+ toolingModelsProvider: ToolingModelsProvider,
+ resolverCtx: ProjectResolverContext
) {
- root.projects.forEach {
- if (it.projectIdentifier.projectPath == ":") {
+ toolingModelsProvider.projects().forEach {
+ val projectIdentifier = it.projectIdentifier.projectPath
+ if (projectIdentifier == ":") {
if (kotlinDslScriptsModelImportSupported(resolverCtx.projectGradleVersion)) {
- resolverCtx.models.getModel(it, KotlinDslScriptsModel::class.java)?.let { model ->
- processScriptModel(resolverCtx, model, it.projectIdentifier.projectPath)
+ val model = toolingModelsProvider.getProjectModel(it, KotlinDslScriptsModel::class.java)
+ if (model != null) {
+ processScriptModel(resolverCtx, model, projectIdentifier)
}
}
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt.193
new file mode 100644
index 0000000..eb3bb6e
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelResolver.kt.193
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scripting.gradle.importing
+
+import com.intellij.openapi.externalSystem.model.DataNode
+import com.intellij.openapi.externalSystem.model.project.ProjectData
+import org.gradle.tooling.model.idea.IdeaProject
+import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
+import org.jetbrains.kotlin.gradle.KotlinDslScriptAdditionalTask
+import org.jetbrains.kotlin.gradle.KotlinDslScriptModelProvider
+import org.jetbrains.kotlin.idea.scripting.gradle.kotlinDslScriptsModelImportSupported
+import org.jetbrains.plugins.gradle.model.Build
+import org.jetbrains.plugins.gradle.model.ClassSetImportModelProvider
+import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
+
+class KotlinDslScriptModelResolver : KotlinDslScriptModelResolverCommon() {
+ override fun requiresTaskRunning() = true
+
+ override fun getModelProvider() = KotlinDslScriptModelProvider()
+
+ override fun getProjectsLoadedModelProvider(): ProjectImportModelProvider? {
+ return ClassSetImportModelProvider(
+ emptySet(),
+ setOf(KotlinDslScriptAdditionalTask::class.java)
+ )
+ }
+
+ override fun populateProjectExtraModels(gradleProject: IdeaProject, ideProject: DataNode<ProjectData>) {
+ super.populateProjectExtraModels(gradleProject, ideProject)
+
+ populateBuildModels(resolverCtx.models.mainBuild, ideProject)
+
+ resolverCtx.models.includedBuilds.forEach { includedRoot ->
+ populateBuildModels(includedRoot, ideProject)
+ }
+ }
+
+ private fun populateBuildModels(
+ root: Build,
+ ideProject: DataNode<ProjectData>
+ ) {
+ root.projects.forEach {
+ if (it.projectIdentifier.projectPath == ":") {
+ if (kotlinDslScriptsModelImportSupported(resolverCtx.projectGradleVersion)) {
+ resolverCtx.models.getModel(it, KotlinDslScriptsModel::class.java)?.let { model ->
+ processScriptModel(resolverCtx, model, it.projectIdentifier.projectPath)
+ }
+ }
+
+ saveGradleBuildEnvironment(resolverCtx)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
index b473aa5..32075c9 100644
--- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
+++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
@@ -147,8 +147,8 @@
}
@NotNull
- private static Set<Class> getToolingExtensionClasses() {
- Set<Class> classes = ContainerUtil.<Class>set(
+ private static Set<Class<?>> getToolingExtensionClasses() {
+ Set<Class<?>> classes = ContainerUtil.set(
ExternalProject.class,
// gradle-tooling-extension-api jar
ProjectImportAction.class,
@@ -163,7 +163,7 @@
}
@NotNull
- private static Set<Class> doGetToolingExtensionClasses() {
+ private static Set<Class<?>> doGetToolingExtensionClasses() {
return Collections.emptySet();
}
@@ -174,7 +174,7 @@
}
}
- protected abstract Set<Class> getModels();
+ protected abstract Set<Class<?>> getModels();
private static void ensureTempDirCreated() throws IOException {
diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193 b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193
new file mode 100644
index 0000000..b473aa5
--- /dev/null
+++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.idea.codeInsight.gradle;
+
+import com.google.common.collect.Multimap;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.StreamUtil;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
+import org.gradle.tooling.BuildActionExecuter;
+import org.gradle.tooling.GradleConnector;
+import org.gradle.tooling.ProjectConnection;
+import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
+import org.gradle.util.GradleVersion;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.model.ClassSetProjectImportModelProvider;
+import org.jetbrains.plugins.gradle.model.ExternalProject;
+import org.jetbrains.plugins.gradle.model.ProjectImportAction;
+import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
+import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeThat;
+
+// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
+@RunWith(value = Parameterized.class)
+public abstract class AbstractModelBuilderTest {
+
+ public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"4.9"}, {"5.6.4"}};
+
+ private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
+
+ private static File ourTempDir;
+
+ @NotNull
+ private final String gradleVersion;
+ private File testDir;
+ private ProjectImportAction.AllModels allModels;
+
+ @Rule public TestName name = new TestName();
+ @Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
+
+ public AbstractModelBuilderTest(@NotNull String gradleVersion) {
+ this.gradleVersion = gradleVersion;
+ }
+
+ @Parameterized.Parameters(name = "{index}: with Gradle-{0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
+ }
+
+
+ @Before
+ public void setUp() throws Exception {
+ assumeThat(gradleVersion, versionMatcherRule.getMatcher());
+
+ ensureTempDirCreated();
+
+ String methodName = name.getMethodName();
+ Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
+ if (m.matches()) {
+ methodName = m.group(1);
+ }
+
+ testDir = new File(ourTempDir, methodName);
+ FileUtil.ensureExists(testDir);
+
+ InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
+ try {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
+ FileUtil.loadTextAndClose(buildScriptStream)
+ );
+ }
+ finally {
+ StreamUtil.closeStream(buildScriptStream);
+ }
+
+ InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
+ try {
+ if (settingsStream != null) {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
+ FileUtil.loadTextAndClose(settingsStream)
+ );
+ }
+ }
+ finally {
+ StreamUtil.closeStream(settingsStream);
+ }
+
+ GradleConnector connector = GradleConnector.newConnector();
+
+ URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
+ connector.useDistribution(distributionUri);
+ connector.forProjectDirectory(testDir);
+ int daemonMaxIdleTime = 10;
+ try {
+ daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
+ }
+ catch (NumberFormatException ignore) {
+ }
+
+ ((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
+ ProjectConnection connection = connector.connect();
+
+ try {
+ ProjectImportAction projectImportAction = new ProjectImportAction(false);
+ projectImportAction.addProjectImportModelProvider(new ClassSetProjectImportModelProvider(getModels()));
+ BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
+ File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
+ assertNotNull(initScript);
+ String jdkHome = IdeaTestUtil.requireRealJdkHome();
+ buildActionExecutor.setJavaHome(new File(jdkHome));
+ buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
+ buildActionExecutor
+ .withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
+ allModels = buildActionExecutor.run();
+ assertNotNull(allModels);
+ }
+ finally {
+ connection.close();
+ }
+ }
+
+ @NotNull
+ private static Set<Class> getToolingExtensionClasses() {
+ Set<Class> classes = ContainerUtil.<Class>set(
+ ExternalProject.class,
+ // gradle-tooling-extension-api jar
+ ProjectImportAction.class,
+ // gradle-tooling-extension-impl jar
+ ModelBuildScriptClasspathBuilderImpl.class,
+ Multimap.class,
+ ShortTypeHandling.class
+ );
+
+ ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
+ return classes;
+ }
+
+ @NotNull
+ private static Set<Class> doGetToolingExtensionClasses() {
+ return Collections.emptySet();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (testDir != null) {
+ FileUtil.delete(testDir);
+ }
+ }
+
+ protected abstract Set<Class> getModels();
+
+
+ private static void ensureTempDirCreated() throws IOException {
+ if (ourTempDir != null) return;
+
+ ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
+ FileUtil.delete(ourTempDir);
+ FileUtil.ensureExists(ourTempDir);
+ }
+
+ public static class DistributionLocator {
+ private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
+ private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
+ private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
+ private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
+
+ @NotNull private final String myReleaseRepoUrl;
+ @NotNull private final String mySnapshotRepoUrl;
+
+ public DistributionLocator() {
+ this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
+ }
+
+ public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
+ myReleaseRepoUrl = releaseRepoUrl;
+ mySnapshotRepoUrl = snapshotRepoUrl;
+ }
+
+ @NotNull
+ public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
+ return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
+ }
+
+ @NotNull
+ private String getDistributionRepository(@NotNull GradleVersion version) {
+ return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
+ }
+
+ private static URI getDistribution(
+ @NotNull String repositoryUrl,
+ @NotNull GradleVersion version,
+ @NotNull String archiveName,
+ @NotNull String archiveClassifier
+ ) throws URISyntaxException {
+ return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
+ }
+
+ @NotNull
+ public static String getRepoUrl(boolean isSnapshotUrl) {
+ String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
+ if (envRepoUrl != null) return envRepoUrl;
+
+ return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
+ }
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
index bf588f6..69903c2 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
@@ -30,15 +30,18 @@
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val toolWindowManager = ToolWindowManager.getInstance(project)
- var toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID)
- if (toolWindow == null) {
- toolWindow = toolWindowManager.registerToolWindow(TOOLWINDOW_ID, false, ToolWindowAnchor.RIGHT)
- toolWindow.icon = KotlinIcons.SMALL_LOGO_13
- val contentManager = toolWindow.contentManager
- val contentFactory = ContentFactory.SERVICE.getInstance()
- contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, toolWindow), "", false))
- }
+ val toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID) ?: toolWindowManager.registerToolWindow(
+ TOOLWINDOW_ID,
+ false,
+ ToolWindowAnchor.RIGHT,
+ )
+ .apply {
+ setIcon(KotlinIcons.SMALL_LOGO_13)
+ val contentFactory = ContentFactory.SERVICE.getInstance()
+ contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, this), "", false))
+ }
+
toolWindow.activate(null)
}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193
new file mode 100644
index 0000000..bf588f6
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193
@@ -0,0 +1,53 @@
+/*
+ * 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.actions
+
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.ui.content.ContentFactory
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.KotlinIcons
+import org.jetbrains.kotlin.idea.internal.KotlinBytecodeToolWindow
+
+class ShowKotlinBytecodeAction : AnAction() {
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ var toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID)
+ if (toolWindow == null) {
+ toolWindow = toolWindowManager.registerToolWindow(TOOLWINDOW_ID, false, ToolWindowAnchor.RIGHT)
+ toolWindow.icon = KotlinIcons.SMALL_LOGO_13
+
+ val contentManager = toolWindow.contentManager
+ val contentFactory = ContentFactory.SERVICE.getInstance()
+ contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, toolWindow), "", false))
+ }
+ toolWindow.activate(null)
+ }
+
+ override fun update(e: AnActionEvent) {
+ val file = e.getData(CommonDataKeys.PSI_FILE)
+ e.presentation.isEnabled = e.project != null && file?.fileType == KotlinFileType.INSTANCE
+ }
+
+ companion object {
+ const val TOOLWINDOW_ID = "Kotlin Bytecode"
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
index 5c0dd47..cebce96 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
@@ -20,12 +20,12 @@
import com.intellij.execution.impl.ConsoleViewImpl
import com.intellij.execution.runners.ExecutionUtil
import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.ide.scratch.ScratchFileType
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.TransactionGuard
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.ex.EditorEx
-import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.wm.ToolWindow
@@ -113,8 +113,8 @@
OpenFileHyperlinkInfo(
project,
psiFile.virtualFile,
- expression.lineStart,
- ),
+ expression.lineStart
+ )
)
print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
}
@@ -149,7 +149,7 @@
toolWindow.show(null)
}
- toolWindow.icon = ExecutionUtil.getLiveIndicator(scratchIcon())
+ toolWindow.setIcon(ExecutionUtil.getLiveIndicator(ScratchFileType.INSTANCE.icon))
}
}
@@ -168,7 +168,7 @@
toolWindow.hide(null)
}
- toolWindow.icon = scratchIcon()
+ toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon is expected to be present"))
}
}
@@ -187,22 +187,18 @@
val project = file.project
val toolWindowManager = ToolWindowManager.getInstance(project)
toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
- val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ val window =
+ toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID) ?: error("ScratchToolWindowFactory.ID should be registered")
ScratchToolWindowFactory().createToolWindowContent(project, window)
- Disposer.register(
- parentDisposable,
- Disposable {
- toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
- },
- )
+ Disposer.register(parentDisposable, Disposable {
+ toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
+ })
return window
}
}
-private fun scratchIcon() = PlainTextFileType.INSTANCE.icon
-
private fun getLineInfo(psiFile: PsiFile, expression: ScratchExpression) =
"${psiFile.name}:${expression.lineStart + 1}"
@@ -213,8 +209,8 @@
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val consoleView = ConsoleViewImpl(project, true)
- toolWindow.isToHideOnEmptyContent = true
- toolWindow.icon = scratchIcon()
+ toolWindow.setToHideOnEmptyContent(true)
+ toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon should be present"))
toolWindow.hide(null)
val contentManager = toolWindow.contentManager
@@ -242,33 +238,27 @@
}
override fun onFinish(file: ScratchFile) {
- TransactionGuard.submitTransaction(
- file.project,
- Runnable {
- val psiFile = file.getPsiFile()
- ?: error(
- "PsiFile cannot be found for scratch to render inlays in tests:\n" +
- "project.isDisposed = ${file.project.isDisposed}\n" +
- "inlays = ${inlays.joinToString { it.second }}\n" +
- "errors = ${errors.joinToString()}",
- )
+ TransactionGuard.submitTransaction(file.project, Runnable {
+ val psiFile = file.getPsiFile()
+ ?: error(
+ "PsiFile cannot be found for scratch to render inlays in tests:\n" +
+ "project.isDisposed = ${file.project.isDisposed}\n" +
+ "inlays = ${inlays.joinToString { it.second }}\n" +
+ "errors = ${errors.joinToString()}"
+ )
- if (inlays.isNotEmpty()) {
- testPrint(
- psiFile,
- inlays.map { (expression, text) ->
- "/** ${getLineInfo(psiFile, expression)} $text */"
- },
- )
- inlays.clear()
- }
+ if (inlays.isNotEmpty()) {
+ testPrint(psiFile, inlays.map { (expression, text) ->
+ "/** ${getLineInfo(psiFile, expression)} $text */"
+ })
+ inlays.clear()
+ }
- if (errors.isNotEmpty()) {
- testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
- errors.clear()
- }
- },
- )
+ if (errors.isNotEmpty()) {
+ testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
+ errors.clear()
+ }
+ })
}
private fun testPrint(file: PsiFile, comments: List<String>) {
@@ -276,7 +266,7 @@
for (comment in comments) {
file.addAfter(
KtPsiFactory(file.project).createComment(comment),
- file.lastChild,
+ file.lastChild
)
}
}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193
new file mode 100644
index 0000000..5c0dd47
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193
@@ -0,0 +1,284 @@
+/*
+ * 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.scratch.output
+
+import com.intellij.execution.filters.OpenFileHyperlinkInfo
+import com.intellij.execution.impl.ConsoleViewImpl
+import com.intellij.execution.runners.ExecutionUtil
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.TransactionGuard
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.editor.ex.EditorEx
+import com.intellij.openapi.fileTypes.PlainTextFileType
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindow
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowFactory
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.idea.scratch.ScratchExpression
+import org.jetbrains.kotlin.idea.scratch.ScratchFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+
+/**
+ * Method to retrieve shared instance of scratches ToolWindow output handler.
+ *
+ * [releaseToolWindowHandler] must be called for every output handler received from this method.
+ *
+ * Can be called from EDT only.
+ *
+ * @return new toolWindow output handler if one does not exist, otherwise returns the existing one. When application in test mode,
+ * returns [TestOutputHandler].
+ */
+fun requestToolWindowHandler(): ScratchOutputHandler {
+ return if (ApplicationManager.getApplication().isUnitTestMode) {
+ TestOutputHandler
+ } else {
+ ScratchToolWindowHandlerKeeper.requestOutputHandler()
+ }
+}
+
+/**
+ * Should be called once with the output handler received from the [requestToolWindowHandler] call.
+ *
+ * When release is called for every request, the output handler is actually disposed.
+ *
+ * When application in test mode, does nothing.
+ *
+ * Can be called from EDT only.
+ */
+fun releaseToolWindowHandler(scratchOutputHandler: ScratchOutputHandler) {
+ if (!ApplicationManager.getApplication().isUnitTestMode) {
+ ScratchToolWindowHandlerKeeper.releaseOutputHandler(scratchOutputHandler)
+ }
+}
+
+/**
+ * Implements logic of shared pointer for the toolWindow output handler.
+ *
+ * Not thread safe! Can be used only from the EDT.
+ */
+private object ScratchToolWindowHandlerKeeper {
+ private var toolWindowHandler: ScratchOutputHandler? = null
+ private var toolWindowDisposable = Disposer.newDisposable()
+ private var counter = 0
+
+ fun requestOutputHandler(): ScratchOutputHandler {
+ if (counter == 0) {
+ toolWindowHandler = ToolWindowScratchOutputHandler(toolWindowDisposable)
+ }
+
+ counter += 1
+ return toolWindowHandler!!
+ }
+
+ fun releaseOutputHandler(scratchOutputHandler: ScratchOutputHandler) {
+ require(counter > 0) { "Counter is $counter, nothing to release!" }
+ require(toolWindowHandler === scratchOutputHandler) { "$scratchOutputHandler differs from stored $toolWindowHandler" }
+
+ counter -= 1
+ if (counter == 0) {
+ Disposer.dispose(toolWindowDisposable)
+ toolWindowDisposable = Disposer.newDisposable()
+ toolWindowHandler = null
+ }
+ }
+}
+
+private class ToolWindowScratchOutputHandler(private val parentDisposable: Disposable) : ScratchOutputHandlerAdapter() {
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ printToConsole(file) {
+ val psiFile = file.getPsiFile()
+ if (psiFile != null) {
+ printHyperlink(
+ getLineInfo(psiFile, expression),
+ OpenFileHyperlinkInfo(
+ project,
+ psiFile.virtualFile,
+ expression.lineStart,
+ ),
+ )
+ print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ print(output.text, output.type.convert())
+ }
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ printToConsole(file) {
+ print(message, ConsoleViewContentType.ERROR_OUTPUT)
+ }
+ }
+
+ private fun printToConsole(file: ScratchFile, print: ConsoleViewImpl.() -> Unit) {
+ ApplicationManager.getApplication().invokeLater {
+ val project = file.project.takeIf { !it.isDisposed } ?: return@invokeLater
+
+ val toolWindow = getToolWindow(project) ?: createToolWindow(file)
+
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.print()
+ component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ }
+
+ toolWindow.setAvailable(true, null)
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.show(null)
+ }
+
+ toolWindow.icon = ExecutionUtil.getLiveIndicator(scratchIcon())
+ }
+ }
+
+ override fun clear(file: ScratchFile) {
+ ApplicationManager.getApplication().invokeLater {
+ val toolWindow = getToolWindow(file.project) ?: return@invokeLater
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.clear()
+ }
+ }
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.hide(null)
+ }
+
+ toolWindow.icon = scratchIcon()
+ }
+ }
+
+ private fun ScratchOutputType.convert() = when (this) {
+ ScratchOutputType.OUTPUT -> ConsoleViewContentType.SYSTEM_OUTPUT
+ ScratchOutputType.RESULT -> ConsoleViewContentType.NORMAL_OUTPUT
+ ScratchOutputType.ERROR -> ConsoleViewContentType.ERROR_OUTPUT
+ }
+
+ private fun getToolWindow(project: Project): ToolWindow? {
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ }
+
+ private fun createToolWindow(file: ScratchFile): ToolWindow {
+ val project = file.project
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
+ val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ ScratchToolWindowFactory().createToolWindowContent(project, window)
+
+ Disposer.register(
+ parentDisposable,
+ Disposable {
+ toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
+ },
+ )
+
+ return window
+ }
+}
+
+private fun scratchIcon() = PlainTextFileType.INSTANCE.icon
+
+private fun getLineInfo(psiFile: PsiFile, expression: ScratchExpression) =
+ "${psiFile.name}:${expression.lineStart + 1}"
+
+private class ScratchToolWindowFactory : ToolWindowFactory {
+ companion object {
+ const val ID = "Scratch Output"
+ }
+
+ override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
+ val consoleView = ConsoleViewImpl(project, true)
+ toolWindow.isToHideOnEmptyContent = true
+ toolWindow.icon = scratchIcon()
+ toolWindow.hide(null)
+
+ val contentManager = toolWindow.contentManager
+ val content = contentManager.factory.createContent(consoleView.component, null, false)
+ contentManager.addContent(content)
+ val editor = consoleView.editor
+ if (editor is EditorEx) {
+ editor.isRendererMode = true
+ }
+
+ Disposer.register(project, consoleView)
+ }
+}
+
+private object TestOutputHandler : ScratchOutputHandlerAdapter() {
+ private val errors = arrayListOf<String>()
+ private val inlays = arrayListOf<Pair<ScratchExpression, String>>()
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ inlays.add(expression to output.text)
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ errors.add(message)
+ }
+
+ override fun onFinish(file: ScratchFile) {
+ TransactionGuard.submitTransaction(
+ file.project,
+ Runnable {
+ val psiFile = file.getPsiFile()
+ ?: error(
+ "PsiFile cannot be found for scratch to render inlays in tests:\n" +
+ "project.isDisposed = ${file.project.isDisposed}\n" +
+ "inlays = ${inlays.joinToString { it.second }}\n" +
+ "errors = ${errors.joinToString()}",
+ )
+
+ if (inlays.isNotEmpty()) {
+ testPrint(
+ psiFile,
+ inlays.map { (expression, text) ->
+ "/** ${getLineInfo(psiFile, expression)} $text */"
+ },
+ )
+ inlays.clear()
+ }
+
+ if (errors.isNotEmpty()) {
+ testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
+ errors.clear()
+ }
+ },
+ )
+ }
+
+ private fun testPrint(file: PsiFile, comments: List<String>) {
+ WriteCommandAction.runWriteCommandAction(file.project) {
+ for (comment in comments) {
+ file.addAfter(
+ KtPsiFactory(file.project).createComment(comment),
+ file.lastChild,
+ )
+ }
+ }
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
index 43aae0c..d990603 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
@@ -22,7 +22,6 @@
import com.intellij.ui.JBSplitter;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinJvmBundle;
@@ -473,7 +472,6 @@
}
@Deprecated
- @ApiStatus.ScheduledForRemoval
public void addGutterToTrack(@NotNull EditorGutterComponentEx gutterComponentEx) {}
public void refresh() {
@@ -481,7 +479,6 @@
}
@Deprecated
- @ApiStatus.ScheduledForRemoval
@Override
public void dispose() {}
}
\ No newline at end of file
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193
new file mode 100644
index 0000000..43aae0c
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scratch.ui;
+
+
+import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
+import com.intellij.openapi.fileEditor.*;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.ui.JBSplitter;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.idea.KotlinJvmBundle;
+
+import javax.swing.*;
+import java.awt.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Two panel editor with three states: Editor, Preview and Editor with Preview.
+ * Based on SplitFileEditor by Valentin Fondaratov
+ * <p/>
+ * <b>NOTE:</b> This class is a copy of {@link com.intellij.openapi.fileEditor.TextEditorWithPreview} from the most recent intellij-community
+ * repository. We cannot use bundled version of this class because it doesn't yet have customization methods
+ * (namely {@link TextEditorWithPreview#createLeftToolbarActionGroup()}).
+ * <p/>
+ * {@link SplitEditorToolbar} is also copied from the platform.
+ * <p/>
+ * This class also may have some minimal customizations to allow tracking when its layout have been changed. In the future we hope to
+ * remove this copied class entirely and to use the bundled version.
+ */
+public class TextEditorWithPreview extends UserDataHolderBase implements FileEditor {
+ protected final TextEditor myEditor;
+ protected final FileEditor myPreview;
+ @NotNull
+ private final MyListenersMultimap myListenersGenerator = new MyListenersMultimap();
+ private Layout myLayout;
+ private JComponent myComponent;
+ private SplitEditorToolbar myToolbarWrapper;
+ private final String myName;
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview, @NotNull String editorName) {
+ myEditor = editor;
+ myPreview = preview;
+ myName = editorName;
+ }
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview) {
+ this(editor, preview, "TextEditorWithPreview");
+ }
+
+ @Nullable
+ @Override
+ public BackgroundEditorHighlighter getBackgroundHighlighter() {
+ return myEditor.getBackgroundHighlighter();
+ }
+
+ @Nullable
+ @Override
+ public FileEditorLocation getCurrentLocation() {
+ return myEditor.getCurrentLocation();
+ }
+
+ @Nullable
+ @Override
+ public StructureViewBuilder getStructureViewBuilder() {
+ return myEditor.getStructureViewBuilder();
+ }
+
+ @Override
+ public void dispose() {
+ Disposer.dispose(myEditor);
+ Disposer.dispose(myPreview);
+ }
+
+ @Override
+ public void selectNotify() {
+ myEditor.selectNotify();
+ myPreview.selectNotify();
+ }
+
+ @Override
+ public void deselectNotify() {
+ myEditor.deselectNotify();
+ myPreview.deselectNotify();
+ }
+
+ @NotNull
+ @Override
+ public JComponent getComponent() {
+ if (myComponent == null) {
+ final JBSplitter splitter = new JBSplitter(false, 0.5f, 0.15f, 0.85f);
+ splitter.setSplitterProportionKey(getSplitterProportionKey());
+ splitter.setFirstComponent(myEditor.getComponent());
+ splitter.setSecondComponent(myPreview.getComponent());
+ splitter.setDividerWidth(3);
+
+ myToolbarWrapper = createMarkdownToolbarWrapper(splitter);
+ Disposer.register(this, myToolbarWrapper);
+
+ if (myLayout == null) {
+ String lastUsed = PropertiesComponent.getInstance().getValue(getLayoutPropertyName());
+ setLayout(Layout.fromName(lastUsed, Layout.SHOW_EDITOR_AND_PREVIEW));
+ }
+ adjustEditorsVisibility();
+
+ myComponent = JBUI.Panels.simplePanel(splitter).addToTop(myToolbarWrapper);
+ }
+ return myComponent;
+ }
+
+ @NotNull
+ private SplitEditorToolbar createMarkdownToolbarWrapper (@NotNull JComponent targetComponentForActions) {
+ final ActionToolbar leftToolbar = createToolbar();
+ if (leftToolbar != null) {
+ leftToolbar.setTargetComponent(targetComponentForActions);
+ leftToolbar.setReservePlaceAutoPopupIcon(false);
+ }
+
+ final ActionToolbar rightToolbar = createRightToolbar();
+ rightToolbar.setTargetComponent(targetComponentForActions);
+ rightToolbar.setReservePlaceAutoPopupIcon(false);
+
+ return new SplitEditorToolbar(leftToolbar, rightToolbar);
+ }
+
+ @Override
+ public void setState(@NotNull FileEditorState state) {
+ if (state instanceof MyFileEditorState) {
+ final MyFileEditorState compositeState = (MyFileEditorState)state;
+ if (compositeState.getFirstState() != null) {
+ myEditor.setState(compositeState.getFirstState());
+ }
+ if (compositeState.getSecondState() != null) {
+ myPreview.setState(compositeState.getSecondState());
+ }
+ if (compositeState.getSplitLayout() != null) {
+ setLayout(compositeState.getSplitLayout());
+ invalidateLayout();
+ }
+ }
+ }
+
+ private void adjustEditorsVisibility() {
+ myEditor.getComponent().setVisible(myLayout == Layout.SHOW_EDITOR || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ myPreview.getComponent().setVisible(myLayout == Layout.SHOW_PREVIEW || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ private void invalidateLayout() {
+ adjustEditorsVisibility();
+ myToolbarWrapper.refresh();
+ myComponent.repaint();
+
+ final JComponent focusComponent = getPreferredFocusedComponent();
+ if (focusComponent != null) {
+ IdeFocusManager.findInstanceByComponent(focusComponent).requestFocus(focusComponent, true);
+ }
+ }
+
+ @NotNull
+ protected String getSplitterProportionKey() {
+ return "TextEditorWithPreview.SplitterProportionKey";
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ switch (myLayout) {
+ case SHOW_EDITOR_AND_PREVIEW:
+ case SHOW_EDITOR:
+ return myEditor.getPreferredFocusedComponent();
+ case SHOW_PREVIEW:
+ return myPreview.getPreferredFocusedComponent();
+ default:
+ throw new IllegalStateException(myLayout.myName);
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ @NotNull
+ @Override
+ public FileEditorState getState(@NotNull FileEditorStateLevel level) {
+ return new MyFileEditorState(myLayout, myEditor.getState(level), myPreview.getState(level));
+ }
+
+ @Override
+ public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.addPropertyChangeListener(listener);
+ myPreview.addPropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.addListenerAndGetDelegate(listener);
+ myEditor.addPropertyChangeListener(delegate);
+ myPreview.addPropertyChangeListener(delegate);
+ }
+
+ @Override
+ public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.removePropertyChangeListener(listener);
+ myPreview.removePropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.removeListenerAndGetDelegate(listener);
+ if (delegate != null) {
+ myEditor.removePropertyChangeListener(delegate);
+ myPreview.removePropertyChangeListener(delegate);
+ }
+ }
+
+ @NotNull
+ public TextEditor getTextEditor() {
+ return myEditor;
+ }
+
+ public Layout getLayout() {
+ return myLayout;
+ }
+
+ protected void setLayout(@NotNull Layout layout) {
+ myLayout = layout;
+ }
+
+ static class MyFileEditorState implements FileEditorState {
+ private final Layout mySplitLayout;
+ private final FileEditorState myFirstState;
+ private final FileEditorState mySecondState;
+
+ MyFileEditorState(Layout layout, FileEditorState firstState, FileEditorState secondState) {
+ mySplitLayout = layout;
+ myFirstState = firstState;
+ mySecondState = secondState;
+ }
+
+ @Nullable
+ public Layout getSplitLayout() {
+ return mySplitLayout;
+ }
+
+ @Nullable
+ public FileEditorState getFirstState() {
+ return myFirstState;
+ }
+
+ @Nullable
+ public FileEditorState getSecondState() {
+ return mySecondState;
+ }
+
+ @Override
+ public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) {
+ return otherState instanceof MyFileEditorState
+ && (myFirstState == null || myFirstState.canBeMergedWith(((MyFileEditorState)otherState).myFirstState, level))
+ && (mySecondState == null || mySecondState.canBeMergedWith(((MyFileEditorState)otherState).mySecondState, level));
+ }
+ }
+
+ @Override
+ public boolean isModified() {
+ return myEditor.isModified() || myPreview.isModified();
+ }
+
+ @Override
+ public boolean isValid() {
+ return myEditor.isValid() && myPreview.isValid();
+ }
+
+ private class DoublingEventListenerDelegate implements PropertyChangeListener {
+ @NotNull
+ private final PropertyChangeListener myDelegate;
+
+ private DoublingEventListenerDelegate(@NotNull PropertyChangeListener delegate) {
+ myDelegate = delegate;
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ myDelegate.propertyChange(
+ new PropertyChangeEvent(TextEditorWithPreview.this, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()));
+ }
+ }
+
+ private class MyListenersMultimap {
+ private final Map<PropertyChangeListener, Pair<Integer, DoublingEventListenerDelegate>> myMap = new HashMap<>();
+
+ @NotNull
+ public DoublingEventListenerDelegate addListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ if (!myMap.containsKey(listener)) {
+ myMap.put(listener, Pair.create(1, new DoublingEventListenerDelegate(listener)));
+ }
+ else {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ myMap.put(listener, Pair.create(oldPair.getFirst() + 1, oldPair.getSecond()));
+ }
+
+ return myMap.get(listener).getSecond();
+ }
+
+ @Nullable
+ public DoublingEventListenerDelegate removeListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ if (oldPair == null) {
+ return null;
+ }
+
+ if (oldPair.getFirst() == 1) {
+ myMap.remove(listener);
+ }
+ else {
+ myMap.put(listener, Pair.create(oldPair.getFirst() - 1, oldPair.getSecond()));
+ }
+ return oldPair.getSecond();
+ }
+ }
+
+ @Nullable
+ protected ActionToolbar createToolbar() {
+ ActionGroup actionGroup = createLeftToolbarActionGroup();
+ if (actionGroup != null) {
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", actionGroup, true);
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Nullable
+ protected ActionGroup createLeftToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ private ActionToolbar createRightToolbar() {
+ final ActionGroup viewActions = createViewActionGroup();
+ final ActionGroup group = createRightToolbarActionGroup();
+ final ActionGroup rightToolbarActions = group == null
+ ? viewActions
+ : new DefaultActionGroup(group, Separator.create(), viewActions);
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", rightToolbarActions, true);
+ }
+
+ @NotNull
+ protected ActionGroup createViewActionGroup() {
+ return new DefaultActionGroup(
+ getShowEditorAction(),
+ getShowEditorAndPreviewAction(),
+ getShowPreviewAction()
+ );
+ }
+
+ @Nullable
+ protected ActionGroup createRightToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR);
+ }
+
+ @NotNull
+ protected ToggleAction getShowPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_PREVIEW);
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAndPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ public enum Layout {
+ SHOW_EDITOR(KotlinJvmBundle.message("editor.editor.only"), AllIcons.General.LayoutEditorOnly),
+ SHOW_PREVIEW(KotlinJvmBundle.message("editor.preview.only"), AllIcons.General.LayoutPreviewOnly),
+ SHOW_EDITOR_AND_PREVIEW(KotlinJvmBundle.message("editor.editor.and.preview"), AllIcons.General.LayoutEditorPreview);
+
+ private final String myName;
+ private final Icon myIcon;
+
+ Layout(String name, Icon icon) {
+ myName = name;
+ myIcon = icon;
+ }
+
+ public static Layout fromName(String name, Layout defaultValue) {
+ for (Layout layout : Layout.values()) {
+ if (layout.myName.equals(name)) {
+ return layout;
+ }
+ }
+ return defaultValue;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public Icon getIcon() {
+ return myIcon;
+ }
+ }
+
+ private class ChangeViewModeAction extends ToggleAction implements DumbAware {
+ private final Layout myActionLayout;
+
+ ChangeViewModeAction(Layout layout) {
+ super(layout.getName(), layout.getName(), layout.getIcon());
+ myActionLayout = layout;
+ }
+
+ @Override
+ public boolean isSelected(@NotNull AnActionEvent e) {
+ return myLayout == myActionLayout;
+ }
+
+ @Override
+ public void setSelected(@NotNull AnActionEvent e, boolean state) {
+ if (state) {
+ setLayout(myActionLayout);
+ PropertiesComponent.getInstance().setValue(getLayoutPropertyName(), myLayout.myName, Layout.SHOW_EDITOR_AND_PREVIEW.myName);
+ adjustEditorsVisibility();
+ }
+ }
+ }
+
+ @NotNull
+ private String getLayoutPropertyName() {
+ return myName + "Layout";
+ }
+}
+
+class SplitEditorToolbar extends JPanel implements Disposable {
+
+ private final ActionToolbar myRightToolbar;
+
+ public SplitEditorToolbar(@Nullable ActionToolbar leftToolbar, @NotNull ActionToolbar rightToolbar) {
+ super(new GridBagLayout());
+ myRightToolbar = rightToolbar;
+
+ if (leftToolbar != null) {
+ add(leftToolbar.getComponent());
+ }
+
+ final JPanel centerPanel = new JPanel(new BorderLayout());
+ add(centerPanel, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,
+ GridBagConstraints.CENTER, GridBagConstraints.BOTH, JBUI.emptyInsets(), 0, 0));
+
+ add(myRightToolbar.getComponent());
+
+ setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIUtil.CONTRAST_BORDER_COLOR));
+
+ if (leftToolbar != null) leftToolbar.updateActionsImmediately();
+ rightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ @ApiStatus.ScheduledForRemoval
+ public void addGutterToTrack(@NotNull EditorGutterComponentEx gutterComponentEx) {}
+
+ public void refresh() {
+ myRightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ @ApiStatus.ScheduledForRemoval
+ @Override
+ public void dispose() {}
+}
\ No newline at end of file
diff --git a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
index 1f4d2a8..d7f1fa7 100644
--- a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
+++ b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
@@ -11,5 +11,5 @@
// FIX ME WHEN BUNCH 193 REMOVED
fun setTemplateTestingCompat(project: Project, disposable: Disposable) {
- TemplateManagerImpl.setTemplateTesting(project, disposable)
+ TemplateManagerImpl.setTemplateTesting(disposable)
}
\ No newline at end of file
diff --git a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193 b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193
new file mode 100644
index 0000000..1f4d2a8
--- /dev/null
+++ b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.liveTemplates
+
+import com.intellij.codeInsight.template.impl.TemplateManagerImpl
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun setTemplateTestingCompat(project: Project, disposable: Disposable) {
+ TemplateManagerImpl.setTemplateTesting(project, disposable)
+}
\ No newline at end of file
diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt
index 6d485c9..73cf9b5 100644
--- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt
+++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt
@@ -16,6 +16,7 @@
import org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject
import java.nio.file.Path
+// FIX ME WHEN BUNCH 201 REMOVED
class IdeaGradleWizardService(private val project: Project) : ProjectImportingWizardService,
IdeaWizardService {
override fun isSuitableFor(buildSystemType: BuildSystemType): Boolean =
diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt.193 b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt.193
new file mode 100644
index 0000000..6d485c9
--- /dev/null
+++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaGradleWizardService.kt.193
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.tools.projectWizard.wizard.service
+
+import com.intellij.openapi.project.Project
+import org.jetbrains.kotlin.tools.projectWizard.core.Reader
+import org.jetbrains.kotlin.tools.projectWizard.core.TaskResult
+import org.jetbrains.kotlin.tools.projectWizard.core.UNIT_SUCCESS
+import org.jetbrains.kotlin.tools.projectWizard.core.service.ProjectImportingWizardService
+import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleIR
+import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType
+import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
+import org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject
+import java.nio.file.Path
+
+class IdeaGradleWizardService(private val project: Project) : ProjectImportingWizardService,
+ IdeaWizardService {
+ override fun isSuitableFor(buildSystemType: BuildSystemType): Boolean =
+ buildSystemType.isGradle
+
+ override fun importProject(
+ reader: Reader,
+ path: Path,
+ modulesIrs: List<ModuleIR>,
+ buildSystem: BuildSystemType
+ ): TaskResult<Unit> {
+ withGradleWrapperEnabled {
+ linkAndRefreshGradleProject(path.toString(), project)
+ }
+ return UNIT_SUCCESS
+ }
+
+ private fun withGradleWrapperEnabled(action: () -> Unit) {
+ val oldGradleDistributionType = System.getProperty("idea.gradle.distributionType")
+ System.setProperty("idea.gradle.distributionType", "WRAPPED")
+ try {
+ action()
+ } finally {
+ if (oldGradleDistributionType != null) {
+ System.setProperty("idea.gradle.distributionType", oldGradleDistributionType)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
index 296417b..573c236 100644
--- a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
+++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
@@ -41,12 +41,14 @@
}
fun compileModule() {
- if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) {
- ProjectTaskManager.getInstance(project).build(module).onSuccess { executionResult ->
- if (!module.isDisposed) {
- KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.hasErrors())
+ if (ExecutionManager.getInstance(project).getContentManager().removeRunContent(executor, contentDescriptor)) {
+ ProjectTaskManager.getInstance(project).build(arrayOf(module), object : ProjectTaskNotification {
+ override fun finished(context: ProjectTaskContext, executionResult: ProjectTaskResult) {
+ if (!module.isDisposed) {
+ KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.errors > 0)
+ }
}
- }
+ })
}
}
}
\ No newline at end of file
diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193 b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193
new file mode 100644
index 0000000..296417b
--- /dev/null
+++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193
@@ -0,0 +1,52 @@
+/*
+ * 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.console
+
+import com.intellij.execution.ExecutionManager
+import com.intellij.execution.Executor
+import com.intellij.execution.ui.RunContentDescriptor
+import com.intellij.openapi.compiler.CompilerManager
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.project.Project
+import com.intellij.task.ProjectTaskContext
+import com.intellij.task.ProjectTaskManager
+import com.intellij.task.ProjectTaskNotification
+import com.intellij.task.ProjectTaskResult
+
+class ConsoleCompilerHelper(
+ private val project: Project,
+ private val module: Module,
+ private val executor: Executor,
+ private val contentDescriptor: RunContentDescriptor
+) {
+
+ fun moduleIsUpToDate(): Boolean {
+ val compilerManager = CompilerManager.getInstance(project)
+ val compilerScope = compilerManager.createModuleCompileScope(module, true)
+ return compilerManager.isUpToDate(compilerScope)
+ }
+
+ fun compileModule() {
+ if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) {
+ ProjectTaskManager.getInstance(project).build(module).onSuccess { executionResult ->
+ if (!module.isDisposed) {
+ KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.hasErrors())
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java
index 7f06004..16a8d2e 100644
--- a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java
+++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java
@@ -25,6 +25,7 @@
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
+import com.intellij.testFramework.IdeaTestUtil;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -49,7 +50,7 @@
@NotNull
@TestOnly
private static Sdk createMockJdk(@NotNull String name, String path) {
- return ((JavaSdkImpl)JavaSdk.getInstance()).createMockJdk(name, path, false);
+ return IdeaTestUtil.createMockJdk(name, path, false);
}
@NotNull
diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java.193 b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java.193
new file mode 100644
index 0000000..7f06004
--- /dev/null
+++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/PluginTestCaseBase.java.193
@@ -0,0 +1,136 @@
+/*
+ * 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.test;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
+import kotlin.jvm.functions.Function0;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.TestOnly;
+import org.jetbrains.kotlin.idea.util.IjPlatformUtil;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+import org.jetbrains.kotlin.test.TestJdkKind;
+
+import java.io.File;
+
+public class PluginTestCaseBase {
+ public static final String TEST_DATA_DIR = "idea/testData";
+ public static final String TEST_DATA_PROJECT_RELATIVE = "/" + TEST_DATA_DIR;
+
+ private PluginTestCaseBase() {
+ }
+
+ @NotNull
+ public static String getTestDataPathBase() {
+ return KotlinTestUtils.getHomeDirectory() + TEST_DATA_PROJECT_RELATIVE;
+ }
+
+ @NotNull
+ @TestOnly
+ private static Sdk createMockJdk(@NotNull String name, String path) {
+ return ((JavaSdkImpl)JavaSdk.getInstance()).createMockJdk(name, path, false);
+ }
+
+ @NotNull
+ private static Sdk getSdk(String sdkHome, String name) {
+ ProjectJdkTable table = IjPlatformUtil.getProjectJdkTableSafe();
+ Sdk existing = table.findJdk(name);
+ if (existing != null) {
+ return existing;
+ }
+ return JavaSdk.getInstance().createJdk(name, sdkHome, true);
+ }
+
+ @NotNull
+ public static Sdk mockJdk() {
+ return getSdk("compiler/testData/mockJDK/jre", "Mock JDK");
+ }
+
+ @NotNull
+ public static Sdk mockJdk6() {
+ return getSdk("compiler/testData/mockJDK/jre", "1.6");
+ }
+
+ @NotNull
+ public static Sdk mockJdk8() {
+ // Using JDK 6, but with version 1.8
+ return getSdk("compiler/testData/mockJDK/jre", "1.8");
+ }
+
+ @TestOnly
+ @NotNull
+ public static Sdk mockJdk9() {
+ return getSdk("compiler/testData/mockJDK9/jre", "9");
+ }
+
+ @NotNull
+ public static Sdk fullJdk() {
+ String javaHome = System.getProperty("java.home");
+ assert new File(javaHome).isDirectory();
+ return getSdk(javaHome, "Full JDK");
+ }
+
+ @NotNull
+ public static Sdk addJdk(@NotNull Disposable disposable, @NotNull Function0<Sdk> getJdk) {
+ Sdk jdk = getJdk.invoke();
+ Sdk[] allJdks = IjPlatformUtil.getProjectJdkTableSafe().getAllJdks();
+ for (Sdk existingJdk : allJdks) {
+ if (existingJdk == jdk) {
+ return existingJdk;
+ }
+ }
+ ApplicationManager.getApplication().runWriteAction(() -> IjPlatformUtil.getProjectJdkTableSafe().addJdk(jdk, disposable));
+ return jdk;
+ }
+
+ @NotNull
+ public static Sdk jdk(@NotNull TestJdkKind kind) {
+ switch (kind) {
+ case MOCK_JDK:
+ return mockJdk();
+ case FULL_JDK_9:
+ String jre9 = KotlinTestUtils.getJdk9Home().getPath();
+ VfsRootAccess.allowRootAccess(jre9);
+ return getSdk(jre9, "Full JDK 9");
+ case FULL_JDK:
+ return fullJdk();
+ default:
+ throw new UnsupportedOperationException(kind.toString());
+ }
+ }
+
+ public static boolean isAllFilesPresentTest(@NotNull String testName) {
+ return StringUtil.startsWithIgnoreCase(testName, "allFilesPresentIn");
+ }
+
+ @TestOnly
+ public static void clearSdkTable(@NotNull Disposable disposable) {
+ Disposer.register(disposable, () -> ApplicationManager.getApplication().runWriteAction(() -> {
+ ProjectJdkTable jdkTable = IjPlatformUtil.getProjectJdkTableSafe();
+ for (Sdk sdk : jdkTable.getAllJdks()) {
+ jdkTable.removeJdk(sdk);
+ }
+ }));
+ }
+}
diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt
index 9e8fc23..2e18b32 100644
--- a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt
+++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt
@@ -17,5 +17,4 @@
// FIX ME WHEN BUNCH 193 REMOVED
fun runPostStartupActivitiesOnce(project: Project) {
- (StartupManager.getInstance(project) as StartupManagerImpl).runPostStartupActivities()
-}
\ No newline at end of file
+}
diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt.193 b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt.193
new file mode 100644
index 0000000..9e8fc23
--- /dev/null
+++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/compat.kt.193
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.test
+
+import com.intellij.codeInsight.daemon.impl.EditorTracker
+import com.intellij.ide.startup.impl.StartupManagerImpl
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.startup.StartupManager
+
+// FIX ME WHEN BUNCH 192 REMOVED
+fun editorTrackerProjectOpened(project: Project) {
+ EditorTracker.getInstance(project)
+}
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun runPostStartupActivitiesOnce(project: Project) {
+ (StartupManager.getInstance(project) as StartupManagerImpl).runPostStartupActivities()
+}
\ No newline at end of file
diff --git a/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt b/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt
index e7796e3..d69db4c 100644
--- a/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt
+++ b/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt
@@ -6,20 +6,22 @@
package org.jetbrains.kotlin.idea.debugger.coroutine.data
import com.intellij.debugger.engine.DebugProcessImpl
-import com.intellij.debugger.engine.JVMStackFrameInfoProvider
+import com.intellij.debugger.engine.JavaStackFrame
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.debugger.memory.utils.StackFrameItem
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
+import com.intellij.xdebugger.XSourcePosition
import com.intellij.xdebugger.frame.XCompositeNode
import com.intellij.xdebugger.frame.XNamedValue
import com.intellij.xdebugger.frame.XStackFrame
import com.intellij.xdebugger.frame.XValueChildrenList
+import com.intellij.xdebugger.impl.frame.XDebuggerFramesList
import com.sun.jdi.Location
import org.jetbrains.kotlin.idea.debugger.*
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.LocationStackFrameProxyImpl
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findPosition
-import org.jetbrains.kotlin.idea.debugger.coroutine.util.isFilteredInvokeSuspend
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
@@ -32,12 +34,12 @@
val first: Boolean
) : CoroutineStackFrameItem(location, emptyList()) {
- override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
return debugProcess.invokeInManagerThread {
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
val locationFrame = LocationStackFrameProxyImpl(location, frame)
val position = location.findPosition(debugProcess.project)
- CreationCoroutineStackFrame(debugProcess, this, first)
+ CreationCoroutineStackFrame(locationFrame, position, first)
}
}
}
@@ -51,18 +53,19 @@
spilledVariables: List<XNamedValue> = emptyList()
) : CoroutineStackFrameItem(location, spilledVariables)
+
/**
* Restored from memory dump
*/
class DefaultCoroutineStackFrameItem(location: Location, spilledVariables: List<XNamedValue>) :
CoroutineStackFrameItem(location, spilledVariables) {
- override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
return debugProcess.invokeInManagerThread {
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
val locationStackFrameProxyImpl = LocationStackFrameProxyImpl(location, frame)
val position = location.findPosition(debugProcess.project) ?: return@invokeInManagerThread null
- CoroutineStackFrame(debugProcess, this)
+ CoroutineStackFrame(locationStackFrameProxyImpl, position, spilledVariables, false)
}
}
}
@@ -82,24 +85,25 @@
open class RunningCoroutineStackFrameItem(
val frame: StackFrameProxyImpl,
spilledVariables: List<XNamedValue> = emptyList()
-) : CoroutineStackFrameItem(frame.location(), spilledVariables), FrameProvider {
- override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+) : CoroutineStackFrameItem(frame.location(), spilledVariables) {
+ override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
return debugProcess.invokeInManagerThread {
- CoroutineStackFrame(debugProcess, this)
+ val position = frame.location().findPosition(debugProcess.project)
+ CoroutineStackFrame(frame, position)
}
}
-
- override fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame? =
- debugProcess.invokeInManagerThread { KotlinStackFrame(frame) }
}
sealed class CoroutineStackFrameItem(val location: Location, val spilledVariables: List<XNamedValue>) :
StackFrameItem(location, spilledVariables) {
val log by logger
- override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
return debugProcess.invokeInManagerThread {
- CoroutineStackFrame(debugProcess, this)
+ val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
+ val locationFrame = LocationStackFrameProxyImpl(location, frame)
+ val position = location.findPosition(debugProcess.project)
+ CoroutineStackFrame(locationFrame, position)
}
}
@@ -108,10 +112,6 @@
location.safeLineNumber() + ":" + location.safeKotlinPreferredLineNumber()
}
-interface FrameProvider {
- fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame?
-}
-
fun DebugProcessImpl.findFirstFrame(): StackFrameProxyImpl? =
suspendManager.pausedContext.thread?.forceFrames()?.firstOrNull()
@@ -123,19 +123,71 @@
*/
class CoroutinePreflightFrame(
val coroutineInfoData: CoroutineInfoData,
- private val frame: StackFrameProxyImpl,
+ val frame: StackFrameProxyImpl,
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
- val mode: SuspendExitMode
-) : KotlinStackFrame(frame), JVMStackFrameInfoProvider {
+ val mode: SuspendExitMode,
+ private val firstFrameVariables: List<XNamedValue> = coroutineInfoData.topFrameVariables()
+) : CoroutineStackFrame(frame, null, firstFrameVariables) {
+
+ override fun isInLibraryContent() = false
+
+ override fun isSynthetic() = false
+
+}
+
+class CreationCoroutineStackFrame(
+ frame: StackFrameProxyImpl,
+ sourcePosition: XSourcePosition?,
+ val first: Boolean
+) : CoroutineStackFrame(frame, sourcePosition, emptyList(), false), XDebuggerFramesList.ItemWithSeparatorAbove {
+
+ override fun getCaptionAboveOf() =
+ KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
+
+ override fun hasSeparatorAbove() =
+ first
+}
+
+open class CoroutineStackFrame(
+ frame: StackFrameProxyImpl,
+ val position: XSourcePosition?,
+ private val spilledVariables: List<XNamedValue>? = null,
+ private val includeFrameVariables: Boolean = true,
+) : KotlinStackFrame(frame) {
+
+ init {
+ descriptor.updateRepresentation(null, DescriptorLabelListener.DUMMY_LISTENER)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+
+ val frame = other as? JavaStackFrame ?: return false
+
+ return descriptor.frameProxy == frame.descriptor.frameProxy
+ }
+
+ override fun hashCode(): Int {
+ return descriptor.frameProxy.hashCode()
+ }
+
+ override fun computeChildren(node: XCompositeNode) {
+ if (includeFrameVariables || spilledVariables == null) {
+ super.computeChildren(node)
+ } else {
+ // ignore original frame variables
+ val list = XValueChildrenList()
+ spilledVariables.forEach { list.add(it) }
+ node.addChildren(list, true)
+ }
+ }
override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
super.superBuildVariables(evaluationContext, children)
- val topRestoredFrame = coroutineInfoData.stackTrace.firstOrNull()
- if (topRestoredFrame != null && topRestoredFrame.location.isFilteredInvokeSuspend()) {
- val firstFrameVariables: List<XNamedValue> = topRestoredFrame.spilledVariables
+ if (spilledVariables != null) {
children.let {
val varNames = (0 until children.size()).map { children.getName(it) }.toSet()
- firstFrameVariables.forEach {
+ spilledVariables.forEach {
if (!varNames.contains(it.name))
children.add(it)
}
@@ -143,32 +195,6 @@
}
}
- override fun isInLibraryContent() = false
-
- override fun isSynthetic() = false
-}
-
-class CreationCoroutineStackFrame(debugProcess: DebugProcessImpl, item: CoroutineStackFrameItem, val first: Boolean) : CoroutineStackFrame(debugProcess, item) {
- override fun getCaptionAboveOf() = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
-
- override fun hasSeparatorAbove(): Boolean =
- first
-}
-
-open class CoroutineStackFrame(val debugProcess: DebugProcessImpl, val item: CoroutineStackFrameItem) :
- StackFrameItem.CapturedStackFrame(debugProcess, item) {
-
- override fun computeChildren(node: XCompositeNode) {
- if (item is FrameProvider)
- item.provideFrame(debugProcess)?.computeChildren(node)
- else
- super.computeChildren(node)
- }
-
- override fun getCaptionAboveOf() = "CoroutineExit"
-
- override fun hasSeparatorAbove(): Boolean =
- false
-}
-
-typealias CoroutineGeneratedFrame = StackFrameItem.CapturedStackFrame
\ No newline at end of file
+ override fun getSourcePosition() =
+ position ?: super.getSourcePosition()
+}
\ No newline at end of file
diff --git a/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt.193 b/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt.193
new file mode 100644
index 0000000..e7796e3
--- /dev/null
+++ b/idea/jvm-debugger/jvm-debugger-coroutine/src/org/jetbrains/kotlin/idea/debugger/coroutine/data/coroutineStackFrameItems.kt.193
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.debugger.coroutine.data
+
+import com.intellij.debugger.engine.DebugProcessImpl
+import com.intellij.debugger.engine.JVMStackFrameInfoProvider
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
+import com.intellij.debugger.jdi.StackFrameProxyImpl
+import com.intellij.debugger.memory.utils.StackFrameItem
+import com.intellij.xdebugger.frame.XCompositeNode
+import com.intellij.xdebugger.frame.XNamedValue
+import com.intellij.xdebugger.frame.XStackFrame
+import com.intellij.xdebugger.frame.XValueChildrenList
+import com.sun.jdi.Location
+import org.jetbrains.kotlin.idea.debugger.*
+import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
+import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.LocationStackFrameProxyImpl
+import org.jetbrains.kotlin.idea.debugger.coroutine.util.findPosition
+import org.jetbrains.kotlin.idea.debugger.coroutine.util.isFilteredInvokeSuspend
+import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
+import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
+
+/**
+ * Creation frame of coroutine either in RUNNING or SUSPENDED state.
+ */
+class CreationCoroutineStackFrameItem(
+ val stackTraceElement: StackTraceElement,
+ location: Location,
+ val first: Boolean
+) : CoroutineStackFrameItem(location, emptyList()) {
+
+ override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ return debugProcess.invokeInManagerThread {
+ val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
+ val locationFrame = LocationStackFrameProxyImpl(location, frame)
+ val position = location.findPosition(debugProcess.project)
+ CreationCoroutineStackFrame(debugProcess, this, first)
+ }
+ }
+}
+
+/**
+ * Restored frame in SUSPENDED coroutine, not attached to any thread.
+ */
+class SuspendCoroutineStackFrameItem(
+ val stackTraceElement: StackTraceElement,
+ location: Location,
+ spilledVariables: List<XNamedValue> = emptyList()
+) : CoroutineStackFrameItem(location, spilledVariables)
+
+/**
+ * Restored from memory dump
+ */
+class DefaultCoroutineStackFrameItem(location: Location, spilledVariables: List<XNamedValue>) :
+ CoroutineStackFrameItem(location, spilledVariables) {
+
+ override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ return debugProcess.invokeInManagerThread {
+ val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
+ val locationStackFrameProxyImpl = LocationStackFrameProxyImpl(location, frame)
+ val position = location.findPosition(debugProcess.project) ?: return@invokeInManagerThread null
+ CoroutineStackFrame(debugProcess, this)
+ }
+ }
+}
+
+/**
+ * Original frame appeared before resumeWith call.
+ *
+ * Sequence is the following
+ *
+ * - KotlinStackFrame
+ * - invokeSuspend(KotlinStackFrame) -|
+ * | replaced with CoroutinePreflightStackFrame
+ * - resumeWith(KotlinStackFrame) ----|
+ * - Kotlin/JavaStackFrame -> PreCoroutineStackFrameItem : CoroutinePreflightStackFrame.threadPreCoroutineFrames
+ *
+ */
+open class RunningCoroutineStackFrameItem(
+ val frame: StackFrameProxyImpl,
+ spilledVariables: List<XNamedValue> = emptyList()
+) : CoroutineStackFrameItem(frame.location(), spilledVariables), FrameProvider {
+ override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ return debugProcess.invokeInManagerThread {
+ CoroutineStackFrame(debugProcess, this)
+ }
+ }
+
+ override fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame? =
+ debugProcess.invokeInManagerThread { KotlinStackFrame(frame) }
+}
+
+sealed class CoroutineStackFrameItem(val location: Location, val spilledVariables: List<XNamedValue>) :
+ StackFrameItem(location, spilledVariables) {
+ val log by logger
+
+ override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
+ return debugProcess.invokeInManagerThread {
+ CoroutineStackFrame(debugProcess, this)
+ }
+ }
+
+ fun uniqueId() =
+ location.safeSourceName() + ":" + location.safeMethod().toString() + ":" +
+ location.safeLineNumber() + ":" + location.safeKotlinPreferredLineNumber()
+}
+
+interface FrameProvider {
+ fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame?
+}
+
+fun DebugProcessImpl.findFirstFrame(): StackFrameProxyImpl? =
+ suspendManager.pausedContext.thread?.forceFrames()?.firstOrNull()
+
+/**
+ * Coroutine exit frame represented by a stack frames
+ * invokeSuspend():-1
+ * resumeWith()
+ *
+ */
+class CoroutinePreflightFrame(
+ val coroutineInfoData: CoroutineInfoData,
+ private val frame: StackFrameProxyImpl,
+ val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
+ val mode: SuspendExitMode
+) : KotlinStackFrame(frame), JVMStackFrameInfoProvider {
+
+ override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
+ super.superBuildVariables(evaluationContext, children)
+ val topRestoredFrame = coroutineInfoData.stackTrace.firstOrNull()
+ if (topRestoredFrame != null && topRestoredFrame.location.isFilteredInvokeSuspend()) {
+ val firstFrameVariables: List<XNamedValue> = topRestoredFrame.spilledVariables
+ children.let {
+ val varNames = (0 until children.size()).map { children.getName(it) }.toSet()
+ firstFrameVariables.forEach {
+ if (!varNames.contains(it.name))
+ children.add(it)
+ }
+ }
+ }
+ }
+
+ override fun isInLibraryContent() = false
+
+ override fun isSynthetic() = false
+}
+
+class CreationCoroutineStackFrame(debugProcess: DebugProcessImpl, item: CoroutineStackFrameItem, val first: Boolean) : CoroutineStackFrame(debugProcess, item) {
+ override fun getCaptionAboveOf() = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
+
+ override fun hasSeparatorAbove(): Boolean =
+ first
+}
+
+open class CoroutineStackFrame(val debugProcess: DebugProcessImpl, val item: CoroutineStackFrameItem) :
+ StackFrameItem.CapturedStackFrame(debugProcess, item) {
+
+ override fun computeChildren(node: XCompositeNode) {
+ if (item is FrameProvider)
+ item.provideFrame(debugProcess)?.computeChildren(node)
+ else
+ super.computeChildren(node)
+ }
+
+ override fun getCaptionAboveOf() = "CoroutineExit"
+
+ override fun hasSeparatorAbove(): Boolean =
+ false
+}
+
+typealias CoroutineGeneratedFrame = StackFrameItem.CapturedStackFrame
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
index e9542b8..b2c9e7e 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
@@ -11,8 +11,8 @@
// FIX ME WHEN BUNCH 193 REMOVED
fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Boolean {
if (!dispose) error("dispose should be true")
- return this.forceCloseProject(project, true)
+ return this.forceCloseProject(project)
}
// FIX ME WHEN BUNCH 193 REMOVED
-typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
+typealias TestApplicationManager = com.intellij.testFramework.TestApplicationManager
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193
new file mode 100644
index 0000000..e9542b8
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ex.ProjectManagerEx
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Boolean {
+ if (!dispose) error("dispose should be true")
+ return this.forceCloseProject(project, true)
+}
+
+// FIX ME WHEN BUNCH 193 REMOVED
+typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
index d1d47e8..da3836f 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
@@ -13,11 +13,13 @@
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
+import org.gradle.util.GradleVersion
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.jetbrains.plugins.gradle.util.GradleLog
+import org.jetbrains.plugins.gradle.util.suggestGradleVersion
import java.io.File
import kotlin.test.assertNotNull
@@ -34,14 +36,13 @@
*/
private fun _importProject(projectPath: String, project: Project) {
GradleLog.LOG.info("Import project at $projectPath")
- val projectSdk = ProjectRootManager.getInstance(project).projectSdk
- assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
val gradleProjectSettings = GradleProjectSettings()
+ val gradleVersion = suggestGradleVersion(project) ?: GradleVersion.current()
GradleSettings.getInstance(project).gradleVmOptions =
"-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
- setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
+ setupGradleSettings(project, gradleProjectSettings, projectPath, gradleVersion)
gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
@@ -65,8 +66,6 @@
ExternalSystemUtil.ensureToolWindowInitialized(project, GradleConstants.SYSTEM_ID)
}
}
-
- ExternalProjectsManagerImpl.disableProjectWatcherAutoUpdate(project)
val settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
if (settings.getLinkedProjectSettings(externalProjectPath) == null) {
settings.linkProject(gradleProjectSettings)
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193
new file mode 100644
index 0000000..d1d47e8
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
+import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
+import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectRootManager
+import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
+import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
+import org.jetbrains.plugins.gradle.settings.GradleSettings
+import org.jetbrains.plugins.gradle.util.GradleConstants
+import org.jetbrains.plugins.gradle.util.GradleLog
+import java.io.File
+import kotlin.test.assertNotNull
+
+fun refreshGradleProject(projectPath: String, project: Project) {
+ _importProject(File(projectPath).absolutePath, project)
+
+ dispatchAllInvocationEvents()
+}
+
+const val GRADLE_JDK_NAME = "Gradle JDK"
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
+ */
+private fun _importProject(projectPath: String, project: Project) {
+ GradleLog.LOG.info("Import project at $projectPath")
+ val projectSdk = ProjectRootManager.getInstance(project).projectSdk
+ assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
+ val gradleProjectSettings = GradleProjectSettings()
+
+ GradleSettings.getInstance(project).gradleVmOptions =
+ "-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
+
+ setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
+ gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
+
+ GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
+ linkedProjectSettings.gradleJvm = GRADLE_JDK_NAME
+ }
+
+ _attachGradleProjectAndRefresh(gradleProjectSettings, project)
+}
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.attachGradleProjectAndRefresh(gradleProjectSettings, project)
+ * except everything is MODAL_SYNC
+ */
+private fun _attachGradleProjectAndRefresh(
+ gradleProjectSettings: GradleProjectSettings,
+ project: Project
+) {
+ val externalProjectPath = gradleProjectSettings.externalProjectPath
+ ExternalProjectsManagerImpl.getInstance(project).runWhenInitialized {
+ DumbService.getInstance(project).runWhenSmart {
+ ExternalSystemUtil.ensureToolWindowInitialized(project, GradleConstants.SYSTEM_ID)
+ }
+ }
+
+ ExternalProjectsManagerImpl.disableProjectWatcherAutoUpdate(project)
+ val settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
+ if (settings.getLinkedProjectSettings(externalProjectPath) == null) {
+ settings.linkProject(gradleProjectSettings)
+ }
+
+ StatefulTestGradleProjectRefreshCallback(externalProjectPath, project).use { callback ->
+ ExternalSystemUtil.refreshProject(
+ externalProjectPath,
+ ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
+ .use(ProgressExecutionMode.MODAL_SYNC)
+ .callback(callback)
+ .build()
+ )
+ }
+}
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt
index cffdcbc..d509f73 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt
@@ -8,6 +8,7 @@
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
+import com.intellij.ide.impl.OpenProjectTask
import com.intellij.ide.startup.impl.StartupManagerImpl
import com.intellij.lang.LanguageAnnotators
import com.intellij.lang.LanguageExtensionPoint
@@ -19,6 +20,7 @@
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.startup.StartupManager
+import com.intellij.platform.PlatformProjectOpenProcessor
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.impl.PsiDocumentManagerBase
import com.intellij.testFramework.ExtensionTestUtil
@@ -70,7 +72,7 @@
}
fun loadProjectWithName(path: String, name: String): Project? =
- ProjectManagerEx.getInstanceEx().loadProject(Paths.get(path), name)
+ PlatformProjectOpenProcessor.openExistingProject(Paths.get(path), Paths.get(path), OpenProjectTask(projectName = name))
fun TestApplicationManager.closeProject(project: Project) {
val name = project.name
@@ -92,11 +94,7 @@
}
fun runStartupActivities(project: Project) {
- with(StartupManager.getInstance(project) as StartupManagerImpl) {
- //scheduleInitialVfsRefresh()
- runStartupActivities()
- }
- runPostStartupActivitiesOnce(project)
+ // obsolete
}
fun waitForAllEditorsFinallyLoaded(project: Project) {
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt.193
new file mode 100644
index 0000000..cffdcbc
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/projectRoutines.kt.193
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
+import com.intellij.ide.startup.impl.StartupManagerImpl
+import com.intellij.lang.LanguageAnnotators
+import com.intellij.lang.LanguageExtensionPoint
+import com.intellij.lang.annotation.Annotator
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.openapi.fileEditor.FileDocumentManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ex.ProjectManagerEx
+import com.intellij.openapi.startup.StartupManager
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.impl.PsiDocumentManagerBase
+import com.intellij.testFramework.ExtensionTestUtil
+import com.intellij.testFramework.runInEdtAndWait
+import com.intellij.util.ui.UIUtil
+import org.jetbrains.kotlin.idea.parameterInfo.HintType
+import org.jetbrains.kotlin.idea.perf.util.logMessage
+import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
+import java.nio.file.Paths
+
+fun commitAllDocuments() {
+ val fileDocumentManager = FileDocumentManager.getInstance()
+ runInEdtAndWait {
+ fileDocumentManager.saveAllDocuments()
+ }
+
+ ProjectManagerEx.getInstanceEx().openProjects.forEach { project ->
+ val psiDocumentManagerBase = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
+
+ runInEdtAndWait {
+ psiDocumentManagerBase.clearUncommittedDocuments()
+ psiDocumentManagerBase.commitAllDocuments()
+ }
+ }
+}
+
+fun commitDocument(project: Project, document: Document) {
+ val psiDocumentManagerBase = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
+ runInEdtAndWait {
+ psiDocumentManagerBase.commitDocument(document)
+ }
+}
+
+fun saveDocument(document: Document) {
+ val fileDocumentManager = FileDocumentManager.getInstance()
+
+ runInEdtAndWait {
+ fileDocumentManager.saveDocument(document)
+ }
+}
+
+fun enableHints(enable: Boolean) =
+ HintType.values().forEach { it.option.set(enable) }
+
+fun dispatchAllInvocationEvents() {
+ runInEdtAndWait {
+ UIUtil.dispatchAllInvocationEvents()
+ }
+}
+
+fun loadProjectWithName(path: String, name: String): Project? =
+ ProjectManagerEx.getInstanceEx().loadProject(Paths.get(path), name)
+
+fun TestApplicationManager.closeProject(project: Project) {
+ val name = project.name
+ val startupManagerImpl = StartupManager.getInstance(project) as StartupManagerImpl
+ val daemonCodeAnalyzerSettings = DaemonCodeAnalyzerSettings.getInstance()
+ val daemonCodeAnalyzerImpl = DaemonCodeAnalyzer.getInstance(project) as DaemonCodeAnalyzerImpl
+
+ setDataProvider(null)
+ daemonCodeAnalyzerSettings.isImportHintEnabled = true // return default value to avoid unnecessary save
+ startupManagerImpl.checkCleared()
+ daemonCodeAnalyzerImpl.cleanupAfterTest()
+
+ logMessage { "project '$name' is about to be closed" }
+ dispatchAllInvocationEvents()
+ val projectManagerEx = ProjectManagerEx.getInstanceEx()
+ projectManagerEx.forceCloseProjectEx(project, true)
+
+ logMessage { "project '$name' successfully closed" }
+}
+
+fun runStartupActivities(project: Project) {
+ with(StartupManager.getInstance(project) as StartupManagerImpl) {
+ //scheduleInitialVfsRefresh()
+ runStartupActivities()
+ }
+ runPostStartupActivitiesOnce(project)
+}
+
+fun waitForAllEditorsFinallyLoaded(project: Project) {
+ // routing is obsolete in 192
+}
+
+fun replaceWithCustomHighlighter(parentDisposable: Disposable, fromImplementationClass: String, toImplementationClass: String) {
+ val pointName = ExtensionPointName.create<LanguageExtensionPoint<Annotator>>(LanguageAnnotators.EP_NAME.name)
+ val extensionPoint = pointName.getPoint(null)
+
+ val point = LanguageExtensionPoint<Annotator>()
+ point.language = "kotlin"
+ point.implementationClass = toImplementationClass
+
+ val extensions = extensionPoint.extensions
+ val filteredExtensions =
+ extensions.filter { it.language != "kotlin" || it.implementationClass != fromImplementationClass }
+ .toList()
+ // custom highlighter is already registered if filteredExtensions has the same size as extensions
+ if (filteredExtensions.size < extensions.size) {
+ ExtensionTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
+ }
+}
\ No newline at end of file
diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml
index e0b9060..990be1a 100644
--- a/idea/resources-descriptors/META-INF/plugin.xml
+++ b/idea/resources-descriptors/META-INF/plugin.xml
@@ -13,7 +13,7 @@
<version>@snapshot@</version>
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
- <idea-version since-build="193.4099.13" until-build="193.*"/>
+ <idea-version since-build="202.1" until-build="203.*"/>
<depends>com.intellij.modules.platform</depends>
@@ -35,7 +35,7 @@
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
- <depends>com.intellij.modules.idea</depends>
+ <incompatible-with>com.intellij.modules.androidstudio</incompatible-with>
<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>
@@ -60,12 +60,6 @@
<xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
- <project-components>
- <component>
- <implementation-class>org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener</implementation-class>
- </component>
- </project-components>
-
<extensionPoints>
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
@@ -97,6 +91,8 @@
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
+ <projectService serviceImplementation="org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener"/>
+
<statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
@@ -118,8 +114,12 @@
<completion.ml.model implementation="org.jetbrains.kotlin.idea.completion.ml.KotlinMLRankingProvider"/>
<completion.ml.contextFeatures language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.ml.KotlinContextFeatureProvider"/>
+ <suggestedRefactoringSupport language="kotlin" implementationClass="org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringSupport"/>
- <defaultLiveTemplatesProvider implementation="org.jetbrains.kotlin.idea.liveTemplates.KotlinLiveTemplatesProvider"/>
+ <refactoring.moveInnerHandler language="kotlin"
+ implementationClass="org.jetbrains.kotlin.idea.refactoring.move.MoveKotlinInnerHandler"/>
+
+ <defaultLiveTemplates file="liveTemplates/Kotlin.xml"/>
<fileType name="Kotlin"
implementationClass="org.jetbrains.kotlin.idea.KotlinFileType"
diff --git a/idea/resources-descriptors/META-INF/plugin.xml.193 b/idea/resources-descriptors/META-INF/plugin.xml.193
new file mode 100644
index 0000000..e0b9060
--- /dev/null
+++ b/idea/resources-descriptors/META-INF/plugin.xml.193
@@ -0,0 +1,149 @@
+<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="193.4099.13" until-build="193.*"/>
+
+ <depends>com.intellij.modules.platform</depends>
+
+ <depends optional="true" config-file="junit.xml">JUnit</depends>
+ <depends optional="true" config-file="gradle.xml">com.intellij.gradle</depends>
+ <depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="kotlin-gradle-testing.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="gradle-groovy.xml">org.intellij.groovy</depends>
+ <depends optional="true" config-file="maven-common.xml">org.jetbrains.idea.maven</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="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>
+ <depends optional="true" config-file="completion-stats.xml">com.intellij.stats.completion</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-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <!-- CIDR-PLUGIN-EXCLUDE-END -->
+
+ <xi:include href="native-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <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/*)"/>
+
+ <xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <project-components>
+ <component>
+ <implementation-class>org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener</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>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <applicationService serviceImplementation="org.jetbrains.kotlin.idea.PluginStartupService" />
+
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.PluginStartupActivity"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginStartupActivity" />
+
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.completion.LookupCancelWatcher"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.caches.KotlinPackageContentModificationListener"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent"/>
+
+ <projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/>
+ <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/>
+
+ <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
+ <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/>
+ <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.parameterInfo.custom.KotlinCodeHintsPass$Registrar"/>
+ <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
+
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.refactoring" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.j2k" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.editor" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.migrationTool" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.new.wizard" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.performance" version="1"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.IDESettingsFUSCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.formatter.KotlinFormatterUsageCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.ProjectConfigurationCollector"/>
+
+ <fileTypeUsageSchemaDescriptor schema="Gradle Script" implementationClass="org.jetbrains.kotlin.idea.core.script.KotlinGradleScriptFileTypeSchemaDetector"/>
+
+ <completion.ml.model implementation="org.jetbrains.kotlin.idea.completion.ml.KotlinMLRankingProvider"/>
+ <completion.ml.contextFeatures language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.ml.KotlinContextFeatureProvider"/>
+
+ <defaultLiveTemplatesProvider implementation="org.jetbrains.kotlin.idea.liveTemplates.KotlinLiveTemplatesProvider"/>
+
+ <fileType name="Kotlin"
+ implementationClass="org.jetbrains.kotlin.idea.KotlinFileType"
+ fieldName="INSTANCE"
+ language="kotlin"
+ extensions="kt;kts"/>
+ <fileType name="ARCHIVE" extensions="klib"/>
+ <fileType name="KNM"
+ implementationClass="org.jetbrains.kotlin.idea.klib.KlibMetaFileType"
+ fieldName="INSTANCE"
+ extensions="knm"/>
+ <fileType name="KJSM"
+ implementationClass="org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType"
+ fieldName="INSTANCE"
+ extensions="kjsm"/>
+
+ <fileType name="kotlin_builtins"
+ implementationClass="org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType"
+ fieldName="INSTANCE"
+ extensions="kotlin_builtins;kotlin_metadata"/>
+
+ <fileType name="kotlin_module"
+ implementationClass="org.jetbrains.kotlin.idea.KotlinModuleFileType"
+ fieldName="INSTANCE"
+ extensions="kotlin_module"/>
+ </extensions>
+</idea-plugin>
diff --git a/idea/resources/META-INF/gradle-java.xml b/idea/resources/META-INF/gradle-java.xml
index c0b25a5..5ecfbfc 100644
--- a/idea/resources/META-INF/gradle-java.xml
+++ b/idea/resources/META-INF/gradle-java.xml
@@ -1,64 +1,58 @@
<idea-plugin>
- <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
- <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPSourceSetsFrameworkSupportProvider"/>
- <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
- <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSBrowserFrameworkSupportProvider"/>
- <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSNodeFrameworkSupportProvider"/>
- <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinMPPFrameworkSupportProvider"/>
- <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
- <kotlinDslFrameworkSupport
- implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSBrowserFrameworkSupportProvider"/>
- <kotlinDslFrameworkSupport
- implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSNodeFrameworkSupportProvider"/>
- <pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinNonJvmGutterConfigurator"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver" order="first"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="first"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.commonizer.KotlinCommonizerModelResolver" order="first"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="last"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
- <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleCoroutineDebugProjectResolver" order="last"/>
- <projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
- <projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
- <projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
- <projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
- </extensions>
+ <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPSourceSetsFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSBrowserFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSNodeFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinMPPFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSBrowserFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSNodeFrameworkSupportProvider"/>
+ <pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.commonizer.KotlinCommonizerModelResolver" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleCoroutineDebugProjectResolver" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
+ </extensions>
- <extensions defaultExtensionNs="com.intellij">
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
- <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryDataService"/>
- <externalSystemTaskNotificationListener
- implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslSyncListener"
- />
- <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptNotificationProvider"/>
+ <extensions defaultExtensionNs="com.intellij">
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryDataService"/>
+ <externalSystemTaskNotificationListener
+ implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslSyncListener"
+ />
+ <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptNotificationProvider"/>
- <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestClassGradleConfigurationProducer"/>
- <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestClassGradleConfigurationProducer"/>
- <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestMethodGradleConfigurationProducer"/>
- <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestMethodGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestClassGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestClassGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestMethodGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestMethodGradleConfigurationProducer"/>
- </extensions>
+ </extensions>
- <extensions defaultExtensionNs="org.jetbrains.kotlin">
- <gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
- <gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
- <gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
- <gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
- <gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
- <gradleProjectImportHandler implementation="org.jetbrains.kotlinx.serialization.idea.KotlinSerializationGradleImportHandler"/>
+ <extensions defaultExtensionNs="org.jetbrains.kotlin">
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlinx.serialization.idea.KotlinSerializationGradleImportHandler"/>
- <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
- <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
- <gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
+ <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
+ <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
+ <gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
- <scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsContributor"
- order="first"/>
- <scriptAdditionalIdeaDependenciesProvider
- implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptAdditionalIdeaDependenciesProvider"/>
+ <scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsContributor" order="first"/>
+ <scriptAdditionalIdeaDependenciesProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptAdditionalIdeaDependenciesProvider"/>
- </extensions>
+ </extensions>
</idea-plugin>
diff --git a/idea/resources/META-INF/gradle-java.xml.193 b/idea/resources/META-INF/gradle-java.xml.193
new file mode 100644
index 0000000..c0b25a5
--- /dev/null
+++ b/idea/resources/META-INF/gradle-java.xml.193
@@ -0,0 +1,64 @@
+<idea-plugin>
+ <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPSourceSetsFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSBrowserFrameworkSupportProvider"/>
+ <frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSNodeFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinMPPFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport
+ implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSBrowserFrameworkSupportProvider"/>
+ <kotlinDslFrameworkSupport
+ implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSNodeFrameworkSupportProvider"/>
+ <pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinNonJvmGutterConfigurator"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.commonizer.KotlinCommonizerModelResolver" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleCoroutineDebugProjectResolver" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
+ <projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryDataService"/>
+ <externalSystemTaskNotificationListener
+ implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslSyncListener"
+ />
+ <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptNotificationProvider"/>
+
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestClassGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestClassGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJvmTestMethodGradleConfigurationProducer"/>
+ <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJvmTestMethodGradleConfigurationProducer"/>
+
+ </extensions>
+
+ <extensions defaultExtensionNs="org.jetbrains.kotlin">
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
+ <gradleProjectImportHandler implementation="org.jetbrains.kotlinx.serialization.idea.KotlinSerializationGradleImportHandler"/>
+
+ <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
+ <projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
+ <gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
+
+ <scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsContributor"
+ order="first"/>
+ <scriptAdditionalIdeaDependenciesProvider
+ implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptAdditionalIdeaDependenciesProvider"/>
+
+ </extensions>
+</idea-plugin>
diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml
index 0e9c4af..88b3459 100644
--- a/idea/resources/META-INF/gradle.xml
+++ b/idea/resources/META-INF/gradle.xml
@@ -25,6 +25,8 @@
<orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.idea.gradle.execution.KotlinGradleOrderEnumerationHandler$Factory" order="first"/>
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
<testTasksProvider implementation="org.jetbrains.kotlin.idea.run.KotlinMPPGradleTestTasksProvider"/>
+
+ <projectModelContributor implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelContributor"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
@@ -39,9 +41,9 @@
defaultValue="true"
restartRequired="false"/>
- <registryKey key="kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedBalloon"
- description="Show balloon when script configuration need to be updated along with project need to be imported balloon"
- defaultValue="false"
+ <registryKey key="kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedFloatingNotification"
+ description="Show floating notification in the editor when script configuration need to be updated"
+ defaultValue="true"
restartRequired="false"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleStandaloneScriptActionsManager"/>
@@ -51,5 +53,9 @@
<action id="Kotlin.Gradle.ShowDslLogs" class="org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs"
text="Show Kotlin Gradle DSL Logs" description="Show Kotlin Gradle DSL logs">
</action>
+
+ <action id="LoadConfigurationAction" class="org.jetbrains.kotlin.idea.scripting.gradle.LoadConfigurationAction">
+ <add-to-group group-id="ExternalSystem.ProjectRefreshActionGroup" anchor="first"/>
+ </action>
</actions>
</idea-plugin>
diff --git a/idea/resources/META-INF/gradle.xml.193 b/idea/resources/META-INF/gradle.xml.193
new file mode 100644
index 0000000..0e9c4af
--- /dev/null
+++ b/idea/resources/META-INF/gradle.xml.193
@@ -0,0 +1,55 @@
+<idea-plugin>
+ <extensionPoints>
+ <extensionPoint qualifiedName="org.jetbrains.kotlin.gradleProjectImportHandler" area="IDEA_PROJECT"
+ interface="org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler"/>
+
+ <extensionPoint qualifiedName="org.jetbrains.kotlin.gradleModelFacade"
+ interface="org.jetbrains.kotlin.idea.inspections.gradle.KotlinGradleModelFacade"/>
+ </extensionPoints>
+
+ <extensions defaultExtensionNs="org.jetbrains.kotlin">
+ <buildSystemTypeDetector implementation="org.jetbrains.kotlin.idea.configuration.GradleDetector"/>
+ <scriptDiagnosticFixProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDiagnosticFixProvider"/>
+ <experimentalFeature implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptConfigurationsImportingFeature"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="org.jetbrains.kotlin.scripting.idea">
+ <listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptListener"/>
+
+ <loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
+
+ <scriptingSupport implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
+ <orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.idea.gradle.execution.KotlinGradleOrderEnumerationHandler$Factory" order="first"/>
+ <projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
+ <testTasksProvider implementation="org.jetbrains.kotlin.idea.run.KotlinMPPGradleTestTasksProvider"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <projectTaskRunner implementation="org.jetbrains.kotlin.idea.gradle.execution.KotlinMPPGradleProjectTaskRunner"
+ id="gradle.mpp" order="first, before gradle"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
+ <externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectSettingsDataService"/>
+
+ <registryKey key="kotlin.mpp.tests.force.gradle"
+ description="Run multi-platform tests with Gradle runner even if the platform runner is used by default.
+ This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place."
+ defaultValue="true"
+ restartRequired="false"/>
+
+ <registryKey key="kotlin.gradle.scripts.scriptConfigurationsNeedToBeUpdatedBalloon"
+ description="Show balloon when script configuration need to be updated along with project need to be imported balloon"
+ defaultValue="false"
+ restartRequired="false"/>
+
+ <projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleStandaloneScriptActionsManager"/>
+ </extensions>
+
+ <actions>
+ <action id="Kotlin.Gradle.ShowDslLogs" class="org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs"
+ text="Show Kotlin Gradle DSL Logs" description="Show Kotlin Gradle DSL logs">
+ </action>
+ </actions>
+</idea-plugin>
diff --git a/idea/resources/META-INF/jvm.xml b/idea/resources/META-INF/jvm.xml
index dac1754..a320eca 100644
--- a/idea/resources/META-INF/jvm.xml
+++ b/idea/resources/META-INF/jvm.xml
@@ -1,5 +1,9 @@
<idea-plugin>
+ <extensions defaultExtensionNs="org.jetbrains.uast">
+ <generate.uastCodeGenerationPlugin implementation="org.jetbrains.uast.kotlin.generate.KotlinUastCodeGenerationPlugin"/>
+ </extensions>
+
<extensions defaultExtensionNs="com.intellij">
<postStartupActivity implementation="org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerStartupActivity"/>
<postStartupActivity implementation="org.jetbrains.kotlin.idea.JvmPluginStartupActivity"/>
diff --git a/idea/resources/META-INF/jvm.xml.193 b/idea/resources/META-INF/jvm.xml.193
new file mode 100644
index 0000000..dac1754
--- /dev/null
+++ b/idea/resources/META-INF/jvm.xml.193
@@ -0,0 +1,12 @@
+<idea-plugin>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerStartupActivity"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.JvmPluginStartupActivity"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.compiler.KotlinCompilerStartupActivity"/>
+ <postStartupActivity implementation="org.jetbrains.kotlin.idea.scratch.ScratchFileModuleInfoProvider"/>
+
+ <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerService"/>
+ </extensions>
+
+</idea-plugin>
diff --git a/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt
index ccc2711..96dc277 100644
--- a/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt
+++ b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt
@@ -46,7 +46,7 @@
val project = myFixture.project
val document = myFixture.editor.document
- val data = ExpectedHighlightingData(document, false, false, false, myFixture.file)
+ val data = ExpectedHighlightingData(document, false, false, false)
data.init()
PsiDocumentManager.getInstance(project).commitAllDocuments()
@@ -69,7 +69,7 @@
): List<LineMarkerInfo<*>> {
myFixture.doHighlighting()
- return AbstractLineMarkersTest.checkHighlighting(myFixture.project, documentToAnalyze, expectedHighlighting, expectedFile)
+ return AbstractLineMarkersTest.checkHighlighting(myFixture.file, documentToAnalyze, expectedHighlighting, expectedFile)
}
}
\ No newline at end of file
diff --git a/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt.193 b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt.193
new file mode 100644
index 0000000..ccc2711
--- /dev/null
+++ b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/ScratchLineMarkersTest.kt.193
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scratch
+
+import com.intellij.codeInsight.daemon.LineMarkerInfo
+import com.intellij.ide.scratch.ScratchFileService
+import com.intellij.ide.scratch.ScratchRootType
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.testFramework.ExpectedHighlightingData
+import com.intellij.testFramework.FileEditorManagerTestCase
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.idea.codeInsight.AbstractLineMarkersTest
+import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
+import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest.Companion.configureOptions
+import org.jetbrains.kotlin.idea.util.application.runWriteAction
+import org.jetbrains.kotlin.psi.KtFile
+import java.io.File
+
+abstract class AbstractScratchLineMarkersTest : FileEditorManagerTestCase() {
+ fun doScratchTest(path: String) {
+ val fileText = FileUtil.loadFile(File(path))
+
+ val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile(
+ project,
+ "scratch.kts",
+ KotlinLanguage.INSTANCE,
+ fileText,
+ ScratchFileService.Option.create_if_missing
+ ) ?: error("Couldn't create scratch file")
+
+ myFixture.openFileInEditor(scratchVirtualFile)
+
+ ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
+
+ val scratchFileEditor = getScratchEditorForSelectedFile(FileEditorManager.getInstance(project), myFixture.file.virtualFile)
+ ?: error("Couldn't find scratch panel")
+
+ configureOptions(scratchFileEditor, fileText, null)
+
+ val project = myFixture.project
+ val document = myFixture.editor.document
+
+ val data = ExpectedHighlightingData(document, false, false, false, myFixture.file)
+ data.init()
+
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+
+ val markers = doAndCheckHighlighting(document, data, File(path))
+
+ AbstractLineMarkersTest.assertNavigationElements(myFixture.project, myFixture.file as KtFile, markers)
+ }
+
+ override fun tearDown() {
+ super.tearDown()
+
+ ScratchFileService.getInstance().scratchesMapping.mappings.forEach { file, _ ->
+ runWriteAction { file.delete(this) }
+ }
+ }
+
+ private fun doAndCheckHighlighting(
+ documentToAnalyze: Document, expectedHighlighting: ExpectedHighlightingData, expectedFile: File
+ ): List<LineMarkerInfo<*>> {
+ myFixture.doHighlighting()
+
+ return AbstractLineMarkersTest.checkHighlighting(myFixture.project, documentToAnalyze, expectedHighlighting, expectedFile)
+ }
+
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt
index e1c7159..91c6bd9 100644
--- a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt
@@ -5,5 +5,35 @@
package org.jetbrains.kotlin.idea
+import com.intellij.codeInsight.javadoc.JavaDocExternalFilter
+import com.intellij.psi.PsiDocCommentBase
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtFile
+import java.util.function.Consumer
+
// FIX ME WHEN BUNCH 201 REMOVED
-class KotlinDocumentationProvider : KotlinDocumentationProviderCompatBase()
\ No newline at end of file
+class KotlinDocumentationProvider : KotlinDocumentationProviderCompatBase() {
+
+ override fun collectDocComments(file: PsiFile, sink: Consumer<PsiDocCommentBase>) {
+ if (file !is KtFile) return
+
+ PsiTreeUtil.processElements(file) {
+ val comment = (it as? KtDeclaration)?.docComment
+ if (comment != null) sink.accept(comment)
+ true
+ }
+ }
+
+ override fun generateRenderedDoc(element: PsiElement): String? {
+ val docComment = (element as? KtDeclaration)?.docComment ?: return null
+
+ val result = StringBuilder().also {
+ it.renderKDoc(docComment.getDefaultSection(), docComment.getAllSections())
+ }
+
+ return JavaDocExternalFilter.filterInternalDocInfo(result.toString())
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.193
new file mode 100644
index 0000000..e1c7159
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.193
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea
+
+// FIX ME WHEN BUNCH 201 REMOVED
+class KotlinDocumentationProvider : KotlinDocumentationProviderCompatBase()
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt
index ed8af9e..feae10d 100644
--- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt
@@ -5,7 +5,11 @@
package org.jetbrains.kotlin.idea.codeInsight
-import com.intellij.xml.breadcrumbs.BreadcrumbsInfoProvider
+import com.intellij.ide.ui.UISettings
+import com.intellij.ui.breadcrumbs.BreadcrumbsProvider
// FIX ME WHEN BUNCH 201 REMOVED
-typealias BreadcrumbsProviderCompatBase = BreadcrumbsInfoProvider
\ No newline at end of file
+abstract class BreadcrumbsProviderCompatBase : BreadcrumbsProvider {
+ override fun isShownByDefault(): Boolean =
+ !UISettings.instance.showMembersInNavigationBar
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt.193 b/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt.193
new file mode 100644
index 0000000..ed8af9e
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/BreadcrumbsProviderCompatBase.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.codeInsight
+
+import com.intellij.xml.breadcrumbs.BreadcrumbsInfoProvider
+
+// FIX ME WHEN BUNCH 201 REMOVED
+typealias BreadcrumbsProviderCompatBase = BreadcrumbsInfoProvider
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
index fef84de..5493af0 100644
--- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
@@ -24,8 +24,8 @@
import org.jetbrains.kotlin.idea.util.application.runWriteAction
class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
- override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
- if (usages != null && usages.isNotEmpty()) {
+ override fun prepareOperation(usages: Array<out UsageInfo>): Any? {
+ if (usages.isNotEmpty()) {
val project = usages[0].project
prepareDelayedRequests(project)
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193 b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193
new file mode 100644
index 0000000..fef84de
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193
@@ -0,0 +1,38 @@
+/*
+ * 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.codeInsight
+
+import com.intellij.openapi.project.Project
+import com.intellij.refactoring.RefactoringHelper
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
+import org.jetbrains.kotlin.idea.codeInsight.shorten.prepareDelayedRequests
+import org.jetbrains.kotlin.idea.util.application.runWriteAction
+
+class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
+ override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
+ if (usages != null && usages.isNotEmpty()) {
+ val project = usages[0].project
+ prepareDelayedRequests(project)
+ }
+ return null
+ }
+
+ override fun performOperation(project: Project, operationData: Any?) {
+ runWriteAction { performDelayedRefactoringRequests(project) }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt
index 859d225..6f479b9 100644
--- a/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt
@@ -75,35 +75,35 @@
object KotlinUsageTypes {
// types
- val TYPE_CONSTRAINT = UsageType(KotlinBundle.message("find.usages.type.type.constraint"))
- val VALUE_PARAMETER_TYPE = UsageType(KotlinBundle.message("find.usages.type.value.parameter.type"))
- val NON_LOCAL_PROPERTY_TYPE = UsageType(KotlinBundle.message("find.usages.type.nonLocal.property.type"))
- val FUNCTION_RETURN_TYPE = UsageType(KotlinBundle.message("find.usages.type.function.return.type"))
- val SUPER_TYPE = UsageType(KotlinBundle.message("find.usages.type.superType"))
- val IS = UsageType(KotlinBundle.message("find.usages.type.is"))
- val CLASS_OBJECT_ACCESS = UsageType(KotlinBundle.message("find.usages.type.class.object"))
- val COMPANION_OBJECT_ACCESS = UsageType(KotlinBundle.message("find.usages.type.companion.object"))
- val EXTENSION_RECEIVER_TYPE = UsageType(KotlinBundle.message("find.usages.type.extension.receiver.type"))
- val SUPER_TYPE_QUALIFIER = UsageType(KotlinBundle.message("find.usages.type.super.type.qualifier"))
- val TYPE_ALIAS = UsageType(KotlinBundle.message("find.usages.type.type.alias"))
+ val TYPE_CONSTRAINT = UsageType(KotlinBundle.lazyMessage("find.usages.type.type.constraint"))
+ val VALUE_PARAMETER_TYPE = UsageType(KotlinBundle.lazyMessage("find.usages.type.value.parameter.type"))
+ val NON_LOCAL_PROPERTY_TYPE = UsageType(KotlinBundle.lazyMessage("find.usages.type.nonLocal.property.type"))
+ val FUNCTION_RETURN_TYPE = UsageType(KotlinBundle.lazyMessage("find.usages.type.function.return.type"))
+ val SUPER_TYPE = UsageType(KotlinBundle.lazyMessage("find.usages.type.superType"))
+ val IS = UsageType(KotlinBundle.lazyMessage("find.usages.type.is"))
+ val CLASS_OBJECT_ACCESS = UsageType(KotlinBundle.lazyMessage("find.usages.type.class.object"))
+ val COMPANION_OBJECT_ACCESS = UsageType(KotlinBundle.lazyMessage("find.usages.type.companion.object"))
+ val EXTENSION_RECEIVER_TYPE = UsageType(KotlinBundle.lazyMessage("find.usages.type.extension.receiver.type"))
+ val SUPER_TYPE_QUALIFIER = UsageType(KotlinBundle.lazyMessage("find.usages.type.super.type.qualifier"))
+ val TYPE_ALIAS = UsageType(KotlinBundle.lazyMessage("find.usages.type.type.alias"))
// functions
- val FUNCTION_CALL = UsageType(KotlinBundle.message("find.usages.type.function.call"))
- val IMPLICIT_GET = UsageType(KotlinBundle.message("find.usages.type.implicit.get"))
- val IMPLICIT_SET = UsageType(KotlinBundle.message("find.usages.type.implicit.set"))
- val IMPLICIT_INVOKE = UsageType(KotlinBundle.message("find.usages.type.implicit.invoke"))
- val IMPLICIT_ITERATION = UsageType(KotlinBundle.message("find.usages.type.implicit.iteration"))
- val PROPERTY_DELEGATION = UsageType(KotlinBundle.message("find.usages.type.property.delegation"))
+ val FUNCTION_CALL = UsageType(KotlinBundle.lazyMessage("find.usages.type.function.call"))
+ val IMPLICIT_GET = UsageType(KotlinBundle.lazyMessage("find.usages.type.implicit.get"))
+ val IMPLICIT_SET = UsageType(KotlinBundle.lazyMessage("find.usages.type.implicit.set"))
+ val IMPLICIT_INVOKE = UsageType(KotlinBundle.lazyMessage("find.usages.type.implicit.invoke"))
+ val IMPLICIT_ITERATION = UsageType(KotlinBundle.lazyMessage("find.usages.type.implicit.iteration"))
+ val PROPERTY_DELEGATION = UsageType(KotlinBundle.lazyMessage("find.usages.type.property.delegation"))
// values
- val RECEIVER = UsageType(KotlinBundle.message("find.usages.type.receiver"))
- val DELEGATE = UsageType(KotlinBundle.message("find.usages.type.delegate"))
+ val RECEIVER = UsageType(KotlinBundle.lazyMessage("find.usages.type.receiver"))
+ val DELEGATE = UsageType(KotlinBundle.lazyMessage("find.usages.type.delegate"))
// packages
- val PACKAGE_DIRECTIVE = UsageType(KotlinBundle.message("find.usages.type.packageDirective"))
- val PACKAGE_MEMBER_ACCESS = UsageType(KotlinBundle.message("find.usages.type.packageMemberAccess"))
+ val PACKAGE_DIRECTIVE = UsageType(KotlinBundle.lazyMessage("find.usages.type.packageDirective"))
+ val PACKAGE_MEMBER_ACCESS = UsageType(KotlinBundle.lazyMessage("find.usages.type.packageMemberAccess"))
// common usage types
- val CALLABLE_REFERENCE = UsageType(KotlinBundle.message("find.usages.type.callable.reference"))
- val NAMED_ARGUMENT = UsageType(KotlinBundle.message("find.usages.type.named.argument"))
+ val CALLABLE_REFERENCE = UsageType(KotlinBundle.lazyMessage("find.usages.type.callable.reference"))
+ val NAMED_ARGUMENT = UsageType(KotlinBundle.lazyMessage("find.usages.type.named.argument"))
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt.193 b/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt.193
new file mode 100644
index 0000000..859d225
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/KotlinUsageTypeProvider.kt.193
@@ -0,0 +1,109 @@
+/*
+ * 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.findUsages
+
+import com.intellij.psi.PsiElement
+import com.intellij.usages.UsageTarget
+import com.intellij.usages.impl.rules.UsageType
+import com.intellij.usages.impl.rules.UsageTypeProviderEx
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.idea.findUsages.UsageTypeEnum.*
+
+object KotlinUsageTypeProvider : UsageTypeProviderEx {
+ override fun getUsageType(element: PsiElement?): UsageType? = getUsageType(element, UsageTarget.EMPTY_ARRAY)
+
+ override fun getUsageType(element: PsiElement?, targets: Array<out UsageTarget>): UsageType? {
+ val usageType = UsageTypeUtils.getUsageType(element) ?: return null
+ return convertEnumToUsageType(usageType)
+ }
+
+ private fun convertEnumToUsageType(usageType: UsageTypeEnum): UsageType = when (usageType) {
+ TYPE_CONSTRAINT -> KotlinUsageTypes.TYPE_CONSTRAINT
+ VALUE_PARAMETER_TYPE -> KotlinUsageTypes.VALUE_PARAMETER_TYPE
+ NON_LOCAL_PROPERTY_TYPE -> KotlinUsageTypes.NON_LOCAL_PROPERTY_TYPE
+ FUNCTION_RETURN_TYPE -> KotlinUsageTypes.FUNCTION_RETURN_TYPE
+ SUPER_TYPE -> KotlinUsageTypes.SUPER_TYPE
+ IS -> KotlinUsageTypes.IS
+ CLASS_OBJECT_ACCESS -> KotlinUsageTypes.CLASS_OBJECT_ACCESS
+ COMPANION_OBJECT_ACCESS -> KotlinUsageTypes.COMPANION_OBJECT_ACCESS
+ EXTENSION_RECEIVER_TYPE -> KotlinUsageTypes.EXTENSION_RECEIVER_TYPE
+ SUPER_TYPE_QUALIFIER -> KotlinUsageTypes.SUPER_TYPE_QUALIFIER
+ TYPE_ALIAS -> KotlinUsageTypes.TYPE_ALIAS
+
+ FUNCTION_CALL -> KotlinUsageTypes.FUNCTION_CALL
+ IMPLICIT_GET -> KotlinUsageTypes.IMPLICIT_GET
+ IMPLICIT_SET -> KotlinUsageTypes.IMPLICIT_SET
+ IMPLICIT_INVOKE -> KotlinUsageTypes.IMPLICIT_INVOKE
+ IMPLICIT_ITERATION -> KotlinUsageTypes.IMPLICIT_ITERATION
+ PROPERTY_DELEGATION -> KotlinUsageTypes.PROPERTY_DELEGATION
+
+ RECEIVER -> KotlinUsageTypes.RECEIVER
+ DELEGATE -> KotlinUsageTypes.DELEGATE
+
+ PACKAGE_DIRECTIVE -> KotlinUsageTypes.PACKAGE_DIRECTIVE
+ PACKAGE_MEMBER_ACCESS -> KotlinUsageTypes.PACKAGE_MEMBER_ACCESS
+
+ CALLABLE_REFERENCE -> KotlinUsageTypes.CALLABLE_REFERENCE
+
+ READ -> UsageType.READ
+ WRITE -> UsageType.WRITE
+ CLASS_IMPORT -> UsageType.CLASS_IMPORT
+ CLASS_LOCAL_VAR_DECLARATION -> UsageType.CLASS_LOCAL_VAR_DECLARATION
+ TYPE_PARAMETER -> UsageType.TYPE_PARAMETER
+ CLASS_CAST_TO -> UsageType.CLASS_CAST_TO
+ ANNOTATION -> UsageType.ANNOTATION
+ CLASS_NEW_OPERATOR -> UsageType.CLASS_NEW_OPERATOR
+ NAMED_ARGUMENT -> KotlinUsageTypes.NAMED_ARGUMENT
+
+ USAGE_IN_STRING_LITERAL -> UsageType.LITERAL_USAGE
+ }
+}
+
+object KotlinUsageTypes {
+ // types
+ val TYPE_CONSTRAINT = UsageType(KotlinBundle.message("find.usages.type.type.constraint"))
+ val VALUE_PARAMETER_TYPE = UsageType(KotlinBundle.message("find.usages.type.value.parameter.type"))
+ val NON_LOCAL_PROPERTY_TYPE = UsageType(KotlinBundle.message("find.usages.type.nonLocal.property.type"))
+ val FUNCTION_RETURN_TYPE = UsageType(KotlinBundle.message("find.usages.type.function.return.type"))
+ val SUPER_TYPE = UsageType(KotlinBundle.message("find.usages.type.superType"))
+ val IS = UsageType(KotlinBundle.message("find.usages.type.is"))
+ val CLASS_OBJECT_ACCESS = UsageType(KotlinBundle.message("find.usages.type.class.object"))
+ val COMPANION_OBJECT_ACCESS = UsageType(KotlinBundle.message("find.usages.type.companion.object"))
+ val EXTENSION_RECEIVER_TYPE = UsageType(KotlinBundle.message("find.usages.type.extension.receiver.type"))
+ val SUPER_TYPE_QUALIFIER = UsageType(KotlinBundle.message("find.usages.type.super.type.qualifier"))
+ val TYPE_ALIAS = UsageType(KotlinBundle.message("find.usages.type.type.alias"))
+
+ // functions
+ val FUNCTION_CALL = UsageType(KotlinBundle.message("find.usages.type.function.call"))
+ val IMPLICIT_GET = UsageType(KotlinBundle.message("find.usages.type.implicit.get"))
+ val IMPLICIT_SET = UsageType(KotlinBundle.message("find.usages.type.implicit.set"))
+ val IMPLICIT_INVOKE = UsageType(KotlinBundle.message("find.usages.type.implicit.invoke"))
+ val IMPLICIT_ITERATION = UsageType(KotlinBundle.message("find.usages.type.implicit.iteration"))
+ val PROPERTY_DELEGATION = UsageType(KotlinBundle.message("find.usages.type.property.delegation"))
+
+ // values
+ val RECEIVER = UsageType(KotlinBundle.message("find.usages.type.receiver"))
+ val DELEGATE = UsageType(KotlinBundle.message("find.usages.type.delegate"))
+
+ // packages
+ val PACKAGE_DIRECTIVE = UsageType(KotlinBundle.message("find.usages.type.packageDirective"))
+ val PACKAGE_MEMBER_ACCESS = UsageType(KotlinBundle.message("find.usages.type.packageMemberAccess"))
+
+ // common usage types
+ val CALLABLE_REFERENCE = UsageType(KotlinBundle.message("find.usages.type.callable.reference"))
+ val NAMED_ARGUMENT = UsageType(KotlinBundle.message("find.usages.type.named.argument"))
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
index 7fbb513..a8d8434 100644
--- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
@@ -10,5 +10,5 @@
import com.intellij.util.Processor
// FIX ME WHEN BUNCH 193 REMOVED
-typealias UsageInfoProcessor = Processor<UsageInfo>
-typealias SliceUsageProcessor = Processor<SliceUsage>
\ No newline at end of file
+typealias UsageInfoProcessor = Processor<in UsageInfo>
+typealias SliceUsageProcessor = Processor<in SliceUsage>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193
new file mode 100644
index 0000000..7fbb513
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.findUsages.handlers
+
+import com.intellij.slicer.SliceUsage
+import com.intellij.usageView.UsageInfo
+import com.intellij.util.Processor
+
+// FIX ME WHEN BUNCH 193 REMOVED
+typealias UsageInfoProcessor = Processor<UsageInfo>
+typealias SliceUsageProcessor = Processor<SliceUsage>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
index 0b7f867..f107283 100644
--- a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
@@ -3,21 +3,22 @@
* 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("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION", "UnstableApiUsage")
+@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION")
package org.jetbrains.kotlin.idea.hierarchy.calls
import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
// FIX ME WHEN BUNCH 193 REMOVED
fun createCallerMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CallerMethodsTreeStructure {
- return CallerMethodsTreeStructure(project, method, scopeType)
+ return CallerMethodsTreeStructure(project, method as PsiMember, scopeType)
}
// FIX ME WHEN BUNCH 193 REMOVED
fun createCalleeMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CalleeMethodsTreeStructure {
- return CalleeMethodsTreeStructure(project, method, scopeType)
+ return CalleeMethodsTreeStructure(project, method as PsiMember, scopeType)
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193
new file mode 100644
index 0000000..0b7f867
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION", "UnstableApiUsage")
+
+package org.jetbrains.kotlin.idea.hierarchy.calls
+
+import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
+import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiMethod
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun createCallerMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CallerMethodsTreeStructure {
+ return CallerMethodsTreeStructure(project, method, scopeType)
+}
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun createCalleeMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CalleeMethodsTreeStructure {
+ return CalleeMethodsTreeStructure(project, method, scopeType)
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt
index 6e32fa6..85feef0 100644
--- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt
@@ -78,11 +78,11 @@
override fun getTargets() = listOf(target)
- override fun selectTargets(targets: MutableList<PsiElement>, selectionConsumer: Consumer<MutableList<PsiElement>>) {
+ override fun selectTargets(targets: MutableList<out PsiElement>, selectionConsumer: Consumer<in MutableList<out PsiElement>>) {
selectionConsumer.consume(targets)
}
- override fun computeUsages(targets: MutableList<PsiElement>?) {
+ override fun computeUsages(targets: MutableList<out PsiElement>) {
val relevantFunction: KtDeclarationWithBody? =
if (target is KtFunctionLiteral) {
target
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt.193 b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt.193
new file mode 100644
index 0000000..6e32fa6
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightExitPointsHandlerFactory.kt.193
@@ -0,0 +1,174 @@
+/*
+ * 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.highlighter
+
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactoryBase
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.impl.source.tree.LeafPsiElement
+import com.intellij.psi.tree.TokenSet
+import com.intellij.psi.util.PsiTreeUtil
+import com.intellij.util.Consumer
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.references.mainReference
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.parents
+import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsResultOfLambda
+import org.jetbrains.kotlin.resolve.inline.InlineUtil
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+class KotlinHighlightExitPointsHandlerFactory : HighlightUsagesHandlerFactoryBase() {
+ companion object {
+ private val RETURN_AND_THROW = TokenSet.create(KtTokens.RETURN_KEYWORD, KtTokens.THROW_KEYWORD)
+
+ private fun getOnReturnOrThrowUsageHandler(editor: Editor, file: PsiFile, target: PsiElement): HighlightUsagesHandlerBase<*>? {
+ if (target !is LeafPsiElement || target.elementType !in RETURN_AND_THROW) {
+ return null
+ }
+
+ val returnOrThrow = PsiTreeUtil.getParentOfType<KtExpression>(
+ target,
+ KtReturnExpression::class.java,
+ KtThrowExpression::class.java
+ ) ?: return null
+
+ return OnExitUsagesHandler(editor, file, returnOrThrow)
+ }
+
+ private fun getOnLambdaCallUsageHandler(editor: Editor, file: PsiFile, target: PsiElement): HighlightUsagesHandlerBase<*>? {
+ if (target !is LeafPsiElement || target.elementType != KtTokens.IDENTIFIER) {
+ return null
+ }
+
+ val refExpr = target.parent as? KtNameReferenceExpression ?: return null
+ val call = refExpr.parent as? KtCallExpression ?: return null
+ if (call.calleeExpression != refExpr) return null
+
+ val lambda = call.lambdaArguments.singleOrNull() ?: return null
+ val literal = lambda.getLambdaExpression()?.functionLiteral ?: return null
+
+ return OnExitUsagesHandler(editor, file, literal, highlightReferences = true)
+ }
+ }
+
+ override fun createHighlightUsagesHandler(editor: Editor, file: PsiFile, target: PsiElement): HighlightUsagesHandlerBase<*>? {
+ return getOnReturnOrThrowUsageHandler(editor, file, target)
+ ?: getOnLambdaCallUsageHandler(editor, file, target)
+ }
+
+ private class OnExitUsagesHandler(editor: Editor, file: PsiFile, val target: KtExpression, val highlightReferences: Boolean = false) :
+ HighlightUsagesHandlerBase<PsiElement>(editor, file) {
+
+ override fun getTargets() = listOf(target)
+
+ override fun selectTargets(targets: MutableList<PsiElement>, selectionConsumer: Consumer<MutableList<PsiElement>>) {
+ selectionConsumer.consume(targets)
+ }
+
+ override fun computeUsages(targets: MutableList<PsiElement>?) {
+ val relevantFunction: KtDeclarationWithBody? =
+ if (target is KtFunctionLiteral) {
+ target
+ } else {
+ target.getRelevantDeclaration()
+ }
+
+ relevantFunction?.accept(object : KtVisitorVoid() {
+ override fun visitKtElement(element: KtElement) {
+ element.acceptChildren(this)
+ }
+
+ override fun visitExpression(expression: KtExpression) {
+ if (relevantFunction is KtFunctionLiteral) {
+ if (occurrenceForFunctionLiteralReturnExpression(expression)) {
+ return
+ }
+ }
+
+ super.visitExpression(expression)
+ }
+
+ private fun occurrenceForFunctionLiteralReturnExpression(expression: KtExpression): Boolean {
+ if (!KtPsiUtil.isStatement(expression)) return false
+
+ if (expression is KtIfExpression || expression is KtWhenExpression || expression is KtBlockExpression) {
+ return false
+ }
+
+ val bindingContext = expression.analyze(BodyResolveMode.FULL)
+ if (!expression.isUsedAsResultOfLambda(bindingContext)) {
+ return false
+ }
+
+ if (expression.getRelevantDeclaration() != relevantFunction) {
+ return false
+ }
+
+ addOccurrence(expression)
+ return true
+ }
+
+ private fun visitReturnOrThrow(expression: KtExpression) {
+ if (expression.getRelevantDeclaration() == relevantFunction) {
+ addOccurrence(expression)
+ }
+ }
+
+ override fun visitReturnExpression(expression: KtReturnExpression) {
+ visitReturnOrThrow(expression)
+ }
+
+ override fun visitThrowExpression(expression: KtThrowExpression) {
+ visitReturnOrThrow(expression)
+ }
+ })
+ }
+
+ override fun highlightReferences() = highlightReferences
+ }
+}
+
+private fun KtExpression.getRelevantDeclaration(): KtDeclarationWithBody? {
+ if (this is KtReturnExpression) {
+ (this.getTargetLabel()?.mainReference?.resolve() as? KtFunction)?.let {
+ return it
+ }
+ }
+
+ if (this is KtThrowExpression || this is KtReturnExpression) {
+ for (parent in parents) {
+ if (parent is KtDeclarationWithBody) {
+ if (parent is KtPropertyAccessor) {
+ return parent
+ }
+
+ if (InlineUtil.canBeInlineArgument(parent) &&
+ !InlineUtil.isInlinedArgument(parent as KtFunction, parent.analyze(BodyResolveMode.FULL), false)
+ ) {
+ return parent
+ }
+ }
+ }
+
+ return null
+ }
+
+ return parents.filterIsInstance<KtDeclarationWithBody>().firstOrNull()
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt
index 8ba248c..896d4c3 100644
--- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt
@@ -38,11 +38,11 @@
override fun getTargets() = listOf(refExpr)
override fun selectTargets(
- targets: MutableList<KtNameReferenceExpression>,
- selectionConsumer: Consumer<MutableList<KtNameReferenceExpression>>
+ targets: MutableList<out KtNameReferenceExpression>,
+ selectionConsumer: Consumer<in MutableList<out KtNameReferenceExpression>>
) = selectionConsumer.consume(targets)
- override fun computeUsages(targets: MutableList<KtNameReferenceExpression>?) {
+ override fun computeUsages(targets: MutableList<out KtNameReferenceExpression>) {
lambda.accept(
object : KtTreeVisitorVoid() {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt.193 b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt.193
new file mode 100644
index 0000000..8ba248c
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightImplicitItHandlerFactory.kt.193
@@ -0,0 +1,58 @@
+/*
+ * 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.highlighter
+
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactoryBase
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.impl.source.tree.LeafPsiElement
+import com.intellij.util.Consumer
+import org.jetbrains.kotlin.idea.intentions.getLambdaByImplicitItReference
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtNameReferenceExpression
+import org.jetbrains.kotlin.psi.KtSimpleNameExpression
+import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
+
+class KotlinHighlightImplicitItHandlerFactory : HighlightUsagesHandlerFactoryBase() {
+ override fun createHighlightUsagesHandler(editor: Editor, file: PsiFile, target: PsiElement): HighlightUsagesHandlerBase<*>? {
+ if (!(target is LeafPsiElement && target.elementType == KtTokens.IDENTIFIER)) return null
+ val refExpr = target.parent as? KtNameReferenceExpression ?: return null
+ val lambda = getLambdaByImplicitItReference(refExpr) ?: return null
+ return object : HighlightUsagesHandlerBase<KtNameReferenceExpression>(editor, file) {
+ override fun getTargets() = listOf(refExpr)
+
+ override fun selectTargets(
+ targets: MutableList<KtNameReferenceExpression>,
+ selectionConsumer: Consumer<MutableList<KtNameReferenceExpression>>
+ ) = selectionConsumer.consume(targets)
+
+ override fun computeUsages(targets: MutableList<KtNameReferenceExpression>?) {
+ lambda.accept(
+ object : KtTreeVisitorVoid() {
+ override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
+ if (expression is KtNameReferenceExpression && getLambdaByImplicitItReference(expression) == lambda) {
+ addOccurrence(expression)
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt
index 0d5b0b6..f8e64f9 100644
--- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt
@@ -46,7 +46,7 @@
class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement) = null
- override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: LineMarkerInfos) {
+ override fun collectSlowLineMarkers(elements: MutableList<out PsiElement>, result: LineMarkerInfos) {
val markedLineNumbers = HashSet<Int>()
for (element in elements) {
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt.193 b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt.193
new file mode 100644
index 0000000..0d5b0b6
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRecursiveCallLineMarkerProvider.kt.193
@@ -0,0 +1,189 @@
+/*
+ * 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.highlighter
+
+import com.intellij.codeHighlighting.Pass
+import com.intellij.codeInsight.daemon.LineMarkerInfo
+import com.intellij.codeInsight.daemon.LineMarkerProvider
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.editor.markup.GutterIconRenderer
+import com.intellij.openapi.progress.ProgressManager
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
+import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
+import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
+import org.jetbrains.kotlin.lexer.KtToken
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.parents
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.inline.InlineUtil
+import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
+import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
+import org.jetbrains.kotlin.types.expressions.OperatorConventions
+import org.jetbrains.kotlin.util.OperatorNameConventions
+import java.util.*
+
+class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
+ override fun getLineMarkerInfo(element: PsiElement) = null
+
+ override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: LineMarkerInfos) {
+ val markedLineNumbers = HashSet<Int>()
+
+ for (element in elements) {
+ ProgressManager.checkCanceled()
+ if (element is KtElement) {
+ val lineNumber = element.getLineNumber()
+ if (lineNumber !in markedLineNumbers && isRecursiveCall(element)) {
+ markedLineNumbers.add(lineNumber)
+ result.add(RecursiveMethodCallMarkerInfo(getElementForLineMark(element)))
+ }
+ }
+ }
+ }
+
+ private fun getEnclosingFunction(element: KtElement, stopOnNonInlinedLambdas: Boolean): KtNamedFunction? {
+ for (parent in element.parents) {
+ when (parent) {
+ is KtFunctionLiteral -> if (stopOnNonInlinedLambdas && !InlineUtil.isInlinedArgument(
+ parent,
+ parent.analyze(),
+ false
+ )
+ ) return null
+ is KtNamedFunction -> {
+ when (parent.parent) {
+ is KtBlockExpression, is KtClassBody, is KtFile, is KtScript -> return parent
+ else -> if (stopOnNonInlinedLambdas && !InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
+ }
+ }
+ is KtClassOrObject -> return null
+ }
+ }
+ return null
+ }
+
+ private fun isRecursiveCall(element: KtElement): Boolean {
+ if (RecursivePropertyAccessorInspection.isRecursivePropertyAccess(element)) return true
+ if (RecursivePropertyAccessorInspection.isRecursiveSyntheticPropertyAccess(element)) return true
+ // Fast check for names without resolve
+ val resolveName = getCallNameFromPsi(element) ?: return false
+ val enclosingFunction = getEnclosingFunction(element, false) ?: return false
+
+ val enclosingFunctionName = enclosingFunction.name
+ if (enclosingFunctionName != OperatorNameConventions.INVOKE.asString()
+ && enclosingFunctionName != resolveName.asString()
+ ) return false
+
+ // Check that there were no not-inlined lambdas on the way to enclosing function
+ if (enclosingFunction != getEnclosingFunction(element, true)) return false
+
+ val bindingContext = element.analyze()
+ val enclosingFunctionDescriptor = bindingContext[BindingContext.FUNCTION, enclosingFunction] ?: return false
+
+ val call = bindingContext[BindingContext.CALL, element] ?: return false
+ val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, call] ?: return false
+
+ if (resolvedCall.candidateDescriptor.original != enclosingFunctionDescriptor) return false
+
+ fun isDifferentReceiver(receiver: Receiver?): Boolean {
+ if (receiver !is ReceiverValue) return false
+
+ val receiverOwner = receiver.getReceiverTargetDescriptor(bindingContext) ?: return true
+
+ return when (receiverOwner) {
+ is SimpleFunctionDescriptor -> receiverOwner != enclosingFunctionDescriptor
+ is ClassDescriptor -> receiverOwner != enclosingFunctionDescriptor.containingDeclaration
+ else -> return true
+ }
+ }
+
+ if (isDifferentReceiver(resolvedCall.dispatchReceiver)) return false
+ return true
+ }
+
+ private class RecursiveMethodCallMarkerInfo(callElement: PsiElement) : LineMarkerInfo<PsiElement>(
+ callElement,
+ callElement.textRange,
+ AllIcons.Gutter.RecursiveMethod,
+ Pass.LINE_MARKERS,
+ { KotlinBundle.message("highlighter.tool.tip.text.recursive.call") },
+ null,
+ GutterIconRenderer.Alignment.RIGHT
+ ) {
+
+ override fun createGutterRenderer(): GutterIconRenderer? {
+ return object : LineMarkerInfo.LineMarkerGutterIconRenderer<PsiElement>(this) {
+ override fun getClickAction() = null // to place breakpoint on mouse click
+ }
+ }
+ }
+
+}
+
+internal fun getElementForLineMark(callElement: PsiElement): PsiElement =
+ when (callElement) {
+ is KtSimpleNameExpression -> callElement.getReferencedNameElement()
+ else ->
+ // a fallback,
+ //but who knows what to reference in KtArrayAccessExpression ?
+ generateSequence(callElement, { it.firstChild }).last()
+ }
+
+private fun PsiElement.getLineNumber(): Int {
+ return PsiDocumentManager.getInstance(project).getDocument(containingFile)!!.getLineNumber(textOffset)
+}
+
+private fun getCallNameFromPsi(element: KtElement): Name? {
+ when (element) {
+ is KtSimpleNameExpression -> {
+ val elementParent = element.getParent()
+ when (elementParent) {
+ is KtCallExpression -> return Name.identifier(element.getText())
+ is KtOperationExpression -> {
+ val operationReference = elementParent.operationReference
+ if (element == operationReference) {
+ val node = operationReference.getReferencedNameElementType()
+ return if (node is KtToken) {
+ val conventionName = if (elementParent is KtPrefixExpression)
+ OperatorConventions.getNameForOperationSymbol(node, true, false)
+ else
+ OperatorConventions.getNameForOperationSymbol(node)
+
+ conventionName ?: Name.identifier(element.getText())
+ } else {
+ Name.identifier(element.getText())
+ }
+ }
+ }
+ }
+ }
+ is KtArrayAccessExpression ->
+ return OperatorNameConventions.GET
+ is KtThisExpression ->
+ if (element.getParent() is KtCallExpression) {
+ return OperatorNameConventions.INVOKE
+ }
+ }
+
+ return null
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt
index 0b31d4e..c121b41 100644
--- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt
@@ -48,7 +48,7 @@
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? = null
override fun collectSlowLineMarkers(
- elements: MutableList<PsiElement>,
+ elements: MutableList<out PsiElement>,
result: LineMarkerInfos
) {
val markedLineNumbers = HashSet<Int>()
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt.193 b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt.193
new file mode 100644
index 0000000..0b31d4e
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinSuspendCallLineMarkerProvider.kt.193
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter
+
+import com.intellij.codeHighlighting.Pass
+import com.intellij.codeInsight.daemon.LineMarkerInfo
+import com.intellij.codeInsight.daemon.LineMarkerProvider
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.editor.markup.GutterIconRenderer
+import com.intellij.openapi.progress.ProgressManager
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
+import org.jetbrains.kotlin.descriptors.accessors
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.idea.KotlinIcons
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
+import org.jetbrains.kotlin.idea.refactoring.getLineNumber
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingContext.*
+import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
+ private class SuspendCallMarkerInfo(callElement: PsiElement, message: String) : LineMarkerInfo<PsiElement>(
+ callElement,
+ callElement.textRange,
+ KotlinIcons.SUSPEND_CALL,
+ Pass.LINE_MARKERS,
+ { message },
+ null,
+ GutterIconRenderer.Alignment.RIGHT
+ ) {
+ override fun createGutterRenderer(): GutterIconRenderer? {
+ return object : LineMarkerInfo.LineMarkerGutterIconRenderer<PsiElement>(this) {
+ override fun getClickAction(): AnAction? = null
+ }
+ }
+ }
+
+ override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? = null
+
+ override fun collectSlowLineMarkers(
+ elements: MutableList<PsiElement>,
+ result: LineMarkerInfos
+ ) {
+ val markedLineNumbers = HashSet<Int>()
+
+ for (element in elements) {
+ ProgressManager.checkCanceled()
+
+ if (element !is KtExpression) continue
+
+ val containingFile = element.containingFile
+ if (containingFile !is KtFile || containingFile is KtCodeFragment) {
+ continue
+ }
+
+ val lineNumber = element.getLineNumber()
+ if (lineNumber in markedLineNumbers) continue
+ if (!element.hasSuspendCalls()) continue
+
+ markedLineNumbers += lineNumber
+ result += if (element is KtForExpression) {
+ SuspendCallMarkerInfo(
+ getElementForLineMark(element.loopRange!!),
+ KotlinBundle.message("highlighter.message.suspending.iteration")
+ )
+ } else {
+ SuspendCallMarkerInfo(getElementForLineMark(element), KotlinBundle.message("highlighter.message.suspend.function.call"))
+ }
+ }
+ }
+}
+
+private fun KtExpression.isValidCandidateExpression(): Boolean {
+ if (this is KtParenthesizedExpression) return false
+ if (this is KtOperationReferenceExpression || this is KtForExpression || this is KtProperty || this is KtNameReferenceExpression) return true
+ val parent = parent
+ if (parent is KtCallExpression && parent.calleeExpression == this) return true
+ if (this is KtCallExpression && (calleeExpression is KtCallExpression || calleeExpression is KtParenthesizedExpression)) return true
+ return false
+}
+
+fun KtExpression.hasSuspendCalls(bindingContext: BindingContext = analyze(BodyResolveMode.PARTIAL)): Boolean {
+ if (!isValidCandidateExpression()) return false
+
+ return when (this) {
+ is KtForExpression -> {
+ val iteratorResolvedCall = bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange]
+ val loopRangeHasNextResolvedCall = bindingContext[LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange]
+ val loopRangeNextResolvedCall = bindingContext[LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange]
+ listOf(iteratorResolvedCall, loopRangeHasNextResolvedCall, loopRangeNextResolvedCall).any {
+ it?.resultingDescriptor?.isSuspend == true
+ }
+ }
+ is KtProperty -> {
+ if (hasDelegateExpression()) {
+ val variableDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, this] as? VariableDescriptorWithAccessors
+ val accessors = variableDescriptor?.accessors ?: emptyList()
+ accessors.any { accessor ->
+ val delegatedFunctionDescriptor = bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, accessor]?.resultingDescriptor
+ delegatedFunctionDescriptor?.isSuspend == true
+ }
+ } else {
+ false
+ }
+ }
+ else -> {
+ val resolvedCall = getResolvedCall(bindingContext)
+ if ((resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.isSuspend == true) true
+ else {
+ val propertyDescriptor = resolvedCall?.resultingDescriptor as? PropertyDescriptor
+ val s = propertyDescriptor?.fqNameSafe?.asString()
+ s?.startsWith("kotlin.coroutines.") == true && s.endsWith(".coroutineContext")
+ }
+ }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt
index 48f3ff2..062f90e 100644
--- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt
@@ -7,4 +7,4 @@
import com.intellij.codeInsight.daemon.LineMarkerInfo
-typealias LineMarkerInfos = MutableCollection<LineMarkerInfo<*>>
\ No newline at end of file
+typealias LineMarkerInfos = MutableCollection<in LineMarkerInfo<*>>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt.193 b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt.193
new file mode 100644
index 0000000..48f3ff2
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/LineMarkerInfos.kt.193
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter.markers
+
+import com.intellij.codeInsight.daemon.LineMarkerInfo
+
+typealias LineMarkerInfos = MutableCollection<LineMarkerInfo<*>>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt
index 956127d..4a5bbce 100644
--- a/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt
@@ -161,9 +161,9 @@
val settings = CodeStyle.getSettings(project).clone()
settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA = true
settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA_ON_CALL_SITE = true
- CodeStyle.doWithTemporarySettings(project, settings) {
+ CodeStyle.doWithTemporarySettings(project, settings, Runnable {
CodeStyleManager.getInstance(project).reformatRange(element, range.startOffset, range.endOffset)
- }
+ })
}
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt.193 b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt.193
new file mode 100644
index 0000000..956127d
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt.193
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.inspections
+
+import com.intellij.application.options.CodeStyle
+import com.intellij.codeInspection.LocalQuickFix
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiElementVisitor
+import com.intellij.psi.codeStyle.CodeStyleManager
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.idea.formatter.TrailingCommaVisitor
+import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
+import org.jetbrains.kotlin.idea.formatter.trailingComma.*
+import org.jetbrains.kotlin.idea.formatter.trailingCommaAllowedInModule
+import org.jetbrains.kotlin.idea.util.isComma
+import org.jetbrains.kotlin.idea.util.isLineBreak
+import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespaceAndComments
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.psiUtil.*
+import javax.swing.JComponent
+import kotlin.properties.Delegates
+
+class TrailingCommaInspection(
+ @JvmField
+ var addCommaWarning: Boolean = false
+) : AbstractKotlinInspection() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor = object : TrailingCommaVisitor() {
+ override val recursively: Boolean = false
+ private var useTrailingComma by Delegates.notNull<Boolean>()
+
+ override fun process(trailingCommaContext: TrailingCommaContext) {
+ val element = trailingCommaContext.ktElement
+ val kotlinCustomSettings = CodeStyle.getSettings(element.project).kotlinCustomSettings
+ useTrailingComma = kotlinCustomSettings.addTrailingCommaIsAllowedFor(element)
+ when (trailingCommaContext.state) {
+ TrailingCommaState.MISSING, TrailingCommaState.EXISTS -> {
+ checkCommaPosition(element)
+ checkLineBreaks(element)
+ }
+ else -> Unit
+ }
+
+ checkTrailingComma(trailingCommaContext)
+ }
+
+ private fun checkLineBreaks(commaOwner: KtElement) {
+ val first = TrailingCommaHelper.elementBeforeFirstElement(commaOwner)
+ if (first?.nextLeaf(true)?.isLineBreak() == false) {
+ first.nextSibling?.let {
+ registerProblemForLineBreak(commaOwner, it, ProblemHighlightType.INFORMATION)
+ }
+ }
+
+ val last = TrailingCommaHelper.elementAfterLastElement(commaOwner)
+ if (last?.prevLeaf(true)?.isLineBreak() == false) {
+ registerProblemForLineBreak(
+ commaOwner,
+ last,
+ if (addCommaWarning) ProblemHighlightType.GENERIC_ERROR_OR_WARNING else ProblemHighlightType.INFORMATION,
+ )
+ }
+ }
+
+ private fun checkCommaPosition(commaOwner: KtElement) {
+ for (invalidComma in TrailingCommaHelper.findInvalidCommas(commaOwner)) {
+ reportProblem(
+ invalidComma,
+ KotlinBundle.message("inspection.trailing.comma.comma.loses.the.advantages.in.this.position"),
+ KotlinBundle.message("inspection.trailing.comma.fix.comma.position")
+ )
+ }
+ }
+
+ private fun checkTrailingComma(trailingCommaContext: TrailingCommaContext) {
+ val commaOwner = trailingCommaContext.ktElement
+ val trailingCommaOrLastElement = TrailingCommaHelper.trailingCommaOrLastElement(commaOwner) ?: return
+ when (trailingCommaContext.state) {
+ TrailingCommaState.MISSING -> {
+ if (!trailingCommaAllowedInModule(commaOwner)) return
+ reportProblem(
+ trailingCommaOrLastElement,
+ KotlinBundle.message("inspection.trailing.comma.missing.trailing.comma"),
+ KotlinBundle.message("inspection.trailing.comma.add.trailing.comma"),
+ if (addCommaWarning) ProblemHighlightType.GENERIC_ERROR_OR_WARNING else ProblemHighlightType.INFORMATION,
+ )
+ }
+ TrailingCommaState.REDUNDANT -> {
+ reportProblem(
+ trailingCommaOrLastElement,
+ KotlinBundle.message("inspection.trailing.comma.useless.trailing.comma"),
+ KotlinBundle.message("inspection.trailing.comma.remove.trailing.comma"),
+ ProblemHighlightType.LIKE_UNUSED_SYMBOL,
+ checkTrailingCommaSettings = false,
+ )
+ }
+ else -> Unit
+ }
+ }
+
+ private fun reportProblem(
+ commaOrElement: PsiElement,
+ message: String,
+ fixMessage: String,
+ highlightType: ProblemHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ checkTrailingCommaSettings: Boolean = true,
+ ) {
+ val commaOwner = commaOrElement.parent as KtElement
+ // case for KtFunctionLiteral, where PsiWhiteSpace after KtTypeParameterList isn't included in this list
+ val problemOwner = commaOwner.parent
+ holder.registerProblem(
+ problemOwner,
+ message,
+ highlightType.applyCondition(!checkTrailingCommaSettings || useTrailingComma),
+ commaOrElement.textRangeOfCommaOrSymbolAfter.shiftLeft(problemOwner.startOffset),
+ createQuickFix(fixMessage, commaOwner),
+ )
+ }
+
+ private fun registerProblemForLineBreak(
+ commaOwner: KtElement,
+ elementForTextRange: PsiElement,
+ highlightType: ProblemHighlightType,
+ ) {
+ val problemElement = commaOwner.parent
+ holder.registerProblem(
+ problemElement,
+ KotlinBundle.message("inspection.trailing.comma.missing.line.break"),
+ highlightType.applyCondition(useTrailingComma),
+ TextRange.from(elementForTextRange.startOffset, 1).shiftLeft(problemElement.startOffset),
+ createQuickFix(KotlinBundle.message("inspection.trailing.comma.add.line.break"), commaOwner),
+ )
+ }
+
+ private fun ProblemHighlightType.applyCondition(condition: Boolean): ProblemHighlightType = when {
+ ApplicationManager.getApplication().isUnitTestMode -> ProblemHighlightType.GENERIC_ERROR_OR_WARNING
+ condition -> this
+ else -> ProblemHighlightType.INFORMATION
+ }
+
+ private fun createQuickFix(
+ fixMessage: String,
+ commaOwner: KtElement,
+ ): LocalQuickFix = object : LocalQuickFix {
+ val commaOwnerPointer = commaOwner.createSmartPointer()
+
+ override fun getFamilyName(): String = fixMessage
+
+ override fun applyFix(project: Project, problemDescriptor: ProblemDescriptor) {
+ val element = commaOwnerPointer.element ?: return
+ val range = createFormatterTextRange(element)
+ val settings = CodeStyle.getSettings(project).clone()
+ settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA = true
+ settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA_ON_CALL_SITE = true
+ CodeStyle.doWithTemporarySettings(project, settings) {
+ CodeStyleManager.getInstance(project).reformatRange(element, range.startOffset, range.endOffset)
+ }
+ }
+ }
+
+ private fun createFormatterTextRange(commaOwner: KtElement): TextRange {
+ val startElement = TrailingCommaHelper.elementBeforeFirstElement(commaOwner) ?: commaOwner
+ val endElement = TrailingCommaHelper.elementAfterLastElement(commaOwner) ?: commaOwner
+ return TextRange.create(startElement.startOffset, endElement.endOffset)
+ }
+
+ private val PsiElement.textRangeOfCommaOrSymbolAfter: TextRange
+ get() {
+ val textRange = textRange
+ if (isComma) return textRange
+
+ return nextLeaf()?.leafIgnoringWhitespaceAndComments(false)?.endOffset?.takeIf { it > 0 }?.let {
+ TextRange.create(it - 1, it).intersection(textRange)
+ } ?: TextRange.create(textRange.endOffset - 1, textRange.endOffset)
+ }
+ }
+
+ override fun createOptionsPanel(): JComponent? {
+ val panel = MultipleCheckboxOptionsPanel(this)
+ panel.addCheckbox(KotlinBundle.message("inspection.trailing.comma.report.also.a.missing.comma"), "addCommaWarning")
+ return panel
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt
index 14c48d2..c579452 100644
--- a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt
@@ -5,14 +5,28 @@
package org.jetbrains.kotlin.idea.navigationToolbar
-import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
+import com.intellij.ide.navigationToolbar.StructureAwareNavBarModelExtension
+import com.intellij.lang.Language
import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.idea.KotlinIconProvider
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.psi.KtFile
// FIX ME WHEN BUNCH 193 REMOVED
-abstract class AbstractNavBarModelExtensionCompatBase : AbstractNavBarModelExtension() {
+abstract class AbstractNavBarModelExtensionCompatBase : StructureAwareNavBarModelExtension() {
protected abstract fun adjustElementImpl(psiElement: PsiElement?): PsiElement?
override fun adjustElement(psiElement: PsiElement): PsiElement? =
adjustElementImpl(psiElement)
+
+ override val language: Language
+ get() = KotlinLanguage.INSTANCE
+
+ override fun acceptParentFromModel(psiElement: PsiElement?): Boolean {
+ if (psiElement is KtFile) {
+ return KotlinIconProvider.getSingleClass(psiElement) == null
+ }
+ return true
+ }
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt.193 b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt.193
new file mode 100644
index 0000000..14c48d2
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/AbstractNavBarModelExtensionCompatBase.kt.193
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.navigationToolbar
+
+import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
+import com.intellij.psi.PsiElement
+
+// FIX ME WHEN BUNCH 193 REMOVED
+abstract class AbstractNavBarModelExtensionCompatBase : AbstractNavBarModelExtension() {
+
+ protected abstract fun adjustElementImpl(psiElement: PsiElement?): PsiElement?
+
+ override fun adjustElement(psiElement: PsiElement): PsiElement? =
+ adjustElementImpl(psiElement)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
index e05f305..eab0909 100644
--- a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
@@ -8,4 +8,4 @@
import com.intellij.ide.util.treeView.AbstractTreeNode
// FIX ME WHEN BUNCH 193 REMOVED
-typealias AbstractTreeNodeAny = AbstractTreeNode<Any>
\ No newline at end of file
+typealias AbstractTreeNodeAny = AbstractTreeNode<*>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193
new file mode 100644
index 0000000..e05f305
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.projectView
+
+import com.intellij.ide.util.treeView.AbstractTreeNode
+
+// FIX ME WHEN BUNCH 193 REMOVED
+typealias AbstractTreeNodeAny = AbstractTreeNode<Any>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java
index b62633a..4c0d1a7 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.util.TextOccurrencesUtil;
import com.intellij.usageView.UsageInfo;
@@ -20,6 +21,7 @@
boolean searchInNonJavaFiles,
String newQName,
Collection<? super UsageInfo> results) {
- TextOccurrencesUtil.findNonCodeUsages(element, stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
+ TextOccurrencesUtil.findNonCodeUsages(element, GlobalSearchScope.projectScope(element.getProject()),
+ stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
}
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java.193
new file mode 100644
index 0000000..b62633a
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/BunchedDeprecation.java.193
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.changeSignature;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.refactoring.util.TextOccurrencesUtil;
+import com.intellij.usageView.UsageInfo;
+
+import java.util.Collection;
+
+// FIX ME WHEN BUNCH 201 REMOVED
+final class BunchedDeprecation {
+ public static void findNonCodeUsages(
+ PsiElement element,
+ String stringToSearch,
+ boolean searchInStringsAndComments,
+ boolean searchInNonJavaFiles,
+ String newQName,
+ Collection<? super UsageInfo> results) {
+ TextOccurrencesUtil.findNonCodeUsages(element, stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt
index 1d3bb5d..1cfcb1d 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt
@@ -42,7 +42,7 @@
receiver?.let { parameters.add(it) }
}
- override fun getVisibility(): Visibility? {
+ override fun getVisibility(): Visibility {
return original.visibility
}
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt.193
new file mode 100644
index 0000000..1d3bb5d
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinMutableMethodDescriptor.kt.193
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.changeSignature
+
+import org.jetbrains.kotlin.descriptors.Visibility
+
+class KotlinMutableMethodDescriptor(override val original: KotlinMethodDescriptor) : KotlinMethodDescriptor by original {
+ private val parameters: MutableList<KotlinParameterInfo> = original.parameters
+
+ override var receiver: KotlinParameterInfo? = original.receiver
+ set(value: KotlinParameterInfo?) {
+ if (value != null && value !in parameters) {
+ parameters.add(value)
+ }
+ field = value
+ }
+
+ fun addParameter(parameter: KotlinParameterInfo) {
+ parameters.add(parameter)
+ }
+
+ fun addParameter(index: Int, parameter: KotlinParameterInfo) {
+ parameters.add(index, parameter)
+ }
+
+ fun removeParameter(index: Int) {
+ val paramInfo = parameters.removeAt(index)
+ if (paramInfo == receiver) {
+ receiver = null
+ }
+ }
+
+ fun renameParameter(index: Int, newName: String) {
+ parameters[index].name = newName
+ }
+
+ fun clearNonReceiverParameters() {
+ parameters.clear()
+ receiver?.let { parameters.add(it) }
+ }
+
+ override fun getVisibility(): Visibility? {
+ return original.visibility
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt
new file mode 100644
index 0000000..8fcf5cb
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.move
+
+import com.intellij.refactoring.move.moveInner.MoveJavaInnerHandler
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.idea.references.getImportAlias
+
+class MoveKotlinInnerHandler : MoveJavaInnerHandler() {
+
+ override fun preprocessUsages(results: MutableCollection<UsageInfo>?) {
+ results?.removeAll { usageInfo ->
+ usageInfo.element?.references?.any { it.getImportAlias() != null } == true
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinInnerHandler.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java
index a754217..04e417a 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.util.TextOccurrencesUtil;
import com.intellij.usageView.UsageInfo;
@@ -20,6 +21,7 @@
boolean searchInNonJavaFiles,
String newQName,
Collection<? super UsageInfo> results) {
- TextOccurrencesUtil.findNonCodeUsages(element, stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
+ TextOccurrencesUtil.findNonCodeUsages(element, GlobalSearchScope.projectScope(element.getProject()),
+ stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
}
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java.193
new file mode 100644
index 0000000..a754217
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/BunchedDeprecation.java.193
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.refactoring.util.TextOccurrencesUtil;
+import com.intellij.usageView.UsageInfo;
+
+import java.util.Collection;
+
+// FIX ME WHEN BUNCH 201 REMOVED
+final class BunchedDeprecation {
+ public static void findNonCodeUsages(
+ PsiElement element,
+ String stringToSearch,
+ boolean searchInStringsAndComments,
+ boolean searchInNonJavaFiles,
+ String newQName,
+ Collection<? super UsageInfo> results) {
+ TextOccurrencesUtil.findNonCodeUsages(element, stringToSearch, searchInStringsAndComments, searchInNonJavaFiles, newQName, results);
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt
new file mode 100644
index 0000000..46d2003
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt
@@ -0,0 +1,77 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SignatureChangePresentationModel.Effect
+import com.intellij.refactoring.suggested.SignatureChangePresentationModel.TextFragment.Leaf
+import com.intellij.refactoring.suggested.SignaturePresentationBuilder
+
+internal class KotlinSignaturePresentationBuilder(
+ signature: SuggestedRefactoringSupport.Signature,
+ otherSignature: SuggestedRefactoringSupport.Signature,
+ isOldSignature: Boolean
+) : SignaturePresentationBuilder(signature, otherSignature, isOldSignature)
+{
+ override fun buildPresentation() {
+ val declarationType = (signature.additionalData as KotlinSignatureAdditionalData).declarationType
+ val keyword = declarationType.prefixKeyword
+ if (keyword != null) {
+ fragments += Leaf("$keyword ")
+ }
+
+ signature.receiverType?.let {
+ when (val effect = effect(it, otherSignature.receiverType)) {
+ Effect.Modified -> {
+ fragments += Leaf(it, effect)
+ fragments += Leaf(".")
+ }
+
+ else -> {
+ fragments += Leaf("$it.", effect)
+ }
+ }
+ }
+
+ val name = if (declarationType == DeclarationType.SECONDARY_CONSTRUCTOR) "constructor" else signature.name
+ fragments += Leaf(name, effect(signature.name, otherSignature.name))
+
+ if (declarationType.isFunction) {
+ buildParameterList { fragments, parameter, correspondingParameter ->
+ if (parameter.modifiers.isNotEmpty()) {
+ fragments += leaf(parameter.modifiers, correspondingParameter?.modifiers ?: parameter.modifiers)
+ fragments += Leaf(" ")
+ }
+
+ fragments += leaf(parameter.name, correspondingParameter?.name ?: parameter.name)
+
+ fragments += Leaf(": ")
+
+ fragments += leaf(parameter.type, correspondingParameter?.type ?: parameter.type)
+
+ val defaultValue = parameter.defaultValue
+ if (defaultValue != null) {
+ val defaultValueEffect = if (correspondingParameter != null)
+ effect(defaultValue, correspondingParameter.defaultValue)
+ else
+ Effect.None
+ fragments += Leaf(" = ", defaultValueEffect.takeIf { it != Effect.Modified } ?: Effect.None)
+ fragments += Leaf(defaultValue, defaultValueEffect)
+ }
+ }
+ } else {
+ require(signature.parameters.isEmpty())
+ }
+
+ signature.type?.let { type ->
+ when (val effect = effect(type, otherSignature.type)) {
+ Effect.Added, Effect.Removed, Effect.None -> {
+ fragments += Leaf(": ${signature.type}", effect)
+ }
+
+ Effect.Modified -> {
+ fragments += Leaf(": ")
+ fragments += Leaf(type, effect)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt
new file mode 100644
index 0000000..288bb7f
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt
@@ -0,0 +1,237 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.util.Key
+import com.intellij.psi.PsiNamedElement
+import com.intellij.psi.search.LocalSearchScope
+import com.intellij.psi.search.searches.ReferencesSearch
+import com.intellij.psi.util.parents
+import com.intellij.refactoring.suggested.*
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.project.forcedModuleInfo
+import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
+import org.jetbrains.kotlin.psi.psiUtil.hasBody
+import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
+import org.jetbrains.kotlin.renderer.DescriptorRenderer
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.isError
+
+class KotlinSuggestedRefactoringAvailability(refactoringSupport: SuggestedRefactoringSupport) :
+ SuggestedRefactoringAvailability(refactoringSupport)
+{
+ private val HAS_USAGES = Key<Boolean>("KotlinSuggestedRefactoringAvailability.HAS_USAGES")
+
+ override fun amendStateInBackground(state: SuggestedRefactoringState): Iterator<SuggestedRefactoringState> {
+ return iterator {
+ if (state.additionalData[HAS_USAGES] == null) {
+ val declarationCopy = state.restoredDeclarationCopy()
+ val useScope = declarationCopy.useScope
+ if (useScope is LocalSearchScope) {
+ val hasUsages = ReferencesSearch.search(declarationCopy, useScope).findFirst() != null
+ yield(state.withAdditionalData(HAS_USAGES, hasUsages))
+ }
+ }
+ }
+ }
+
+ override fun refineSignaturesWithResolve(state: SuggestedRefactoringState): SuggestedRefactoringState {
+ val newDeclaration = state.declaration as? KtCallableDeclaration ?: return state
+ val oldDeclaration = state.restoredDeclarationCopy() as? KtCallableDeclaration ?: return state
+ oldDeclaration.containingKtFile.forcedModuleInfo = newDeclaration.getModuleInfo()
+
+ val descriptorWithOldSignature = oldDeclaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val descriptorWithNewSignature = newDeclaration.resolveToDescriptorIfAny() as CallableDescriptor
+
+ val oldSignature = state.oldSignature
+ val newSignature = state.newSignature
+
+ val (oldReturnType, newReturnType) = refineType(
+ oldSignature.type,
+ newSignature.type,
+ descriptorWithOldSignature.returnType,
+ descriptorWithNewSignature.returnType
+ )
+
+ val improvedOldParameterTypesById = mutableMapOf<Any, String>()
+ val improvedNewParameterTypesById = mutableMapOf<Any, String>()
+ for (oldParameter in oldSignature.parameters) {
+ val id = oldParameter.id
+ val newParameter = newSignature.parameterById(id) ?: continue
+ val oldIndex = oldSignature.parameterIndex(oldParameter)
+ val newIndex = newSignature.parameterIndex(newParameter)
+ val (oldType, newType) = refineType(
+ oldParameter.type,
+ newParameter.type,
+ descriptorWithOldSignature.valueParameters[oldIndex].type,
+ descriptorWithNewSignature.valueParameters[newIndex].type
+ )
+ // oldType and newType may not be null because arguments of refineType call were all non-null
+ improvedOldParameterTypesById[id] = oldType!!
+ improvedNewParameterTypesById[id] = newType!!
+ }
+ val oldParameters = oldSignature.parameters.map { it.copy(type = improvedOldParameterTypesById[it.id] ?: it.type) }
+ val newParameters = newSignature.parameters.map { it.copy(type = improvedNewParameterTypesById[it.id] ?: it.type) }
+
+ val oldAdditionalData = oldSignature.additionalData as KotlinSignatureAdditionalData?
+ val newAdditionalData = newSignature.additionalData as KotlinSignatureAdditionalData?
+ val (oldReceiverType, newReceiverType) = refineType(
+ oldAdditionalData?.receiverType,
+ newAdditionalData?.receiverType,
+ descriptorWithOldSignature.extensionReceiverParameter?.type,
+ descriptorWithNewSignature.extensionReceiverParameter?.type
+ )
+
+ return state
+ .withOldSignature(
+ Signature.create(oldSignature.name, oldReturnType, oldParameters, oldAdditionalData?.copy(receiverType = oldReceiverType))!!
+ )
+ .withNewSignature(
+ Signature.create(newSignature.name, newReturnType, newParameters, newAdditionalData?.copy(receiverType = newReceiverType))!!
+ )
+ }
+
+ private fun refineType(
+ oldTypeInCode: String?,
+ newTypeInCode: String?,
+ oldTypeResolved: KotlinType?,
+ newTypeResolved: KotlinType?
+ ): Pair<String?, String?> {
+ if (oldTypeResolved?.isError == true || newTypeResolved?.isError == true) {
+ return oldTypeInCode to newTypeInCode
+ }
+
+ val oldTypeFQ = oldTypeResolved?.fqText()
+ val newTypeFQ = newTypeResolved?.fqText()
+
+ if (oldTypeInCode != newTypeInCode) {
+ if (oldTypeFQ == newTypeFQ) {
+ return newTypeInCode to newTypeInCode
+ }
+ } else {
+ if (oldTypeFQ != newTypeFQ) {
+ return oldTypeFQ to newTypeFQ
+ }
+ }
+
+ return oldTypeInCode to newTypeInCode
+ }
+
+ private fun KotlinType.fqText() = DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(this)
+
+ override fun detectAvailableRefactoring(state: SuggestedRefactoringState): SuggestedRefactoringData? {
+ val declaration = state.declaration
+ if (declaration !is KtCallableDeclaration || KotlinSuggestedRefactoringSupport.isOnlyRenameSupported(declaration)) {
+ if (state.additionalData[HAS_USAGES] == false) return null
+ return SuggestedRenameData(declaration as PsiNamedElement, state.oldSignature.name)
+ }
+
+ val overridesName = declaration.overridesName()
+ if (overridesName == null && state.additionalData[HAS_USAGES] == false) return null
+
+ val oldSignature = state.oldSignature
+ val newSignature = state.newSignature
+ val updateUsagesData = SuggestedChangeSignatureData.create(state, USAGES)
+ val updateOverridesData = overridesName?.let { updateUsagesData.copy(nameOfStuffToUpdate = it) }
+
+ if (newSignature.parameters.size > oldSignature.parameters.size) {
+ val newParametersAtEndWithDefaults = newSignature.parameters.drop(oldSignature.parameters.size)
+ .all { oldSignature.parameterById(it.id) == null && it.defaultValue != null }
+ // special case if added new parameters with default values to the end
+ // we don't need to update usages if it's the only change
+ if (newParametersAtEndWithDefaults) {
+ val truncatedNewSignature = Signature.create(
+ newSignature.name,
+ newSignature.type,
+ newSignature.parameters.take(oldSignature.parameters.size),
+ newSignature.additionalData
+ )!!
+ val refactoringData = detectAvailableRefactoring(
+ oldSignature,
+ truncatedNewSignature,
+ updateUsagesData,
+ updateOverridesData,
+ declaration,
+ declaration.valueParameters.take(oldSignature.parameters.size)
+ )
+
+ return when (refactoringData) {
+ is SuggestedChangeSignatureData -> refactoringData
+ is SuggestedRenameData -> updateUsagesData
+ null -> updateOverridesData
+ }
+ }
+ }
+
+ return detectAvailableRefactoring(
+ oldSignature,
+ newSignature,
+ updateUsagesData,
+ updateOverridesData,
+ declaration,
+ declaration.valueParameters
+ )
+ }
+
+ private fun detectAvailableRefactoring(
+ oldSignature: Signature,
+ newSignature: Signature,
+ updateUsagesData: SuggestedChangeSignatureData,
+ updateOverridesData: SuggestedChangeSignatureData?,
+ declaration: PsiNamedElement,
+ parameters: List<KtParameter>
+ ): SuggestedRefactoringData? {
+ if (hasParameterAddedRemovedOrReordered(oldSignature, newSignature)) return updateUsagesData
+
+ // for non-virtual function we can add or remove receiver for usages but not change its type
+ if ((oldSignature.receiverType == null) != (newSignature.receiverType == null)) return updateUsagesData
+
+ val (nameChanges, renameData) = nameChanges(oldSignature, newSignature, declaration, parameters)
+
+ if (hasTypeChanges(oldSignature, newSignature)) {
+ return if (nameChanges > 0)
+ updateUsagesData
+ else
+ updateOverridesData
+ }
+
+ return when {
+ renameData != null -> renameData
+ nameChanges > 0 -> updateUsagesData
+ else -> null
+ }
+ }
+
+ private fun KtCallableDeclaration.overridesName(): String? {
+ return when {
+ hasModifier(KtTokens.ABSTRACT_KEYWORD) -> IMPLEMENTATIONS
+ hasModifier(KtTokens.OPEN_KEYWORD) -> OVERRIDES
+ containingClassOrObject?.isInterfaceClass() == true -> if (hasBody()) OVERRIDES else IMPLEMENTATIONS
+ isExpectDeclaration() -> "actual declarations"
+ else -> null
+ }
+ }
+
+ private fun KtCallableDeclaration.isExpectDeclaration(): Boolean {
+ return parentsWithSelf
+ .filterIsInstance<KtDeclaration>()
+ .takeWhile { it == this || it is KtClassOrObject }
+ .any { it.hasModifier(KtTokens.EXPECT_KEYWORD) }
+ }
+
+ override fun hasTypeChanges(oldSignature: Signature, newSignature: Signature): Boolean {
+ return super.hasTypeChanges(oldSignature, newSignature) || oldSignature.receiverType != newSignature.receiverType
+ }
+
+ override fun hasParameterTypeChanges(oldParam: Parameter, newParam: Parameter): Boolean {
+ return super.hasParameterTypeChanges(oldParam, newParam) || oldParam.modifiers != newParam.modifiers
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt
new file mode 100644
index 0000000..bdc1072
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt
@@ -0,0 +1,148 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.suggested.SuggestedChangeSignatureData
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.types.isError
+import org.jetbrains.kotlin.utils.addIfNotNull
+
+class KotlinSuggestedRefactoringExecution(
+ refactoringSupport: KotlinSuggestedRefactoringSupport
+) : SuggestedRefactoringExecution(refactoringSupport) {
+
+ private data class PrepareChangeSignatureResult(
+ val returnTypeInfo: KotlinTypeInfo,
+ val parameterTypeInfos: List<KotlinTypeInfo>
+ )
+
+ override fun prepareChangeSignature(data: SuggestedChangeSignatureData): Any {
+ val declaration = data.declaration as KtCallableDeclaration
+ val descriptorWithNewSignature = declaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val newSignature = data.newSignature
+
+ val returnType = descriptorWithNewSignature.returnType
+ val returnTypeInfo = if (returnType != null && !returnType.isError) {
+ KotlinTypeInfo(type = returnType, isCovariant = true)
+ } else {
+ KotlinTypeInfo(text = newSignature.type, isCovariant = true)
+ }
+
+ require(descriptorWithNewSignature.valueParameters.size == newSignature.parameters.size) {
+ "Number of parameters of newSignature is ${newSignature.parameters.size} and of the descriptor is ${descriptorWithNewSignature.valueParameters.size}"
+ }
+
+ val parameterTypeInfos = descriptorWithNewSignature.valueParameters.zip(newSignature.parameters)
+ .map { (parameterDescriptor, parameterData) ->
+ val type = parameterDescriptor.varargElementType ?: parameterDescriptor.type
+ if (!type.isError) {
+ KotlinTypeInfo(type = type, isCovariant = true)
+ } else {
+ KotlinTypeInfo(text = parameterData.type, isCovariant = true)
+ }
+ }
+
+ return PrepareChangeSignatureResult(returnTypeInfo, parameterTypeInfos)
+ }
+
+ override fun performChangeSignature(
+ data: SuggestedChangeSignatureData,
+ newParameterValues: List<NewParameterValue>,
+ preparedData: Any?
+ ) {
+ val (returnTypeInfo, parameterTypeInfos) = preparedData as PrepareChangeSignatureResult
+
+ val declaration = data.declaration as KtDeclaration
+ val descriptor = declaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val project = declaration.project
+
+ val configuration = object : KotlinChangeSignatureConfiguration {
+ override fun performSilently(affectedFunctions: Collection<PsiElement>) = true
+ }
+ val changeSignature = KotlinChangeSignature(project, descriptor, configuration, declaration, null)
+ val methodDescriptor = changeSignature.adjustDescriptor(listOf(descriptor))!!
+
+ val parameters = mutableListOf<KotlinParameterInfo>()
+ var newParameterValueIndex = 0
+
+ val receiver: KotlinParameterInfo? = data.newSignature.receiverType?.let { newReceiverType ->
+ val newTypeInfo = KotlinTypeInfo(text = newReceiverType, isCovariant = false)
+ if (data.oldSignature.receiverType != null) {
+ methodDescriptor.receiver!!.apply { currentTypeInfo = newTypeInfo }
+ } else {
+ KotlinParameterInfo(descriptor, -1, "", newTypeInfo).apply {
+ setNewParameterValue(newParameterValues[newParameterValueIndex++])
+ }
+ }
+ }
+
+ parameters.addIfNotNull(receiver)
+
+ val psiFactory = KtPsiFactory(project)
+
+ for ((index, parameter) in data.newSignature.parameters.withIndex()) {
+ val initialIndex = data.oldSignature.parameterById(parameter.id)
+ ?.let { data.oldSignature.parameterIndex(it) }
+
+ val defaultValue = parameter.defaultValue?.let { psiFactory.createExpression(it) }
+
+ val modifierList = parameter.modifiers
+ .takeIf { it.isNotEmpty() }
+ ?.let { psiFactory.createModifierList(it) }
+
+ val parameterInfo = if (initialIndex == null) {
+ KotlinParameterInfo(
+ descriptor,
+ -1,
+ parameter.name,
+ parameterTypeInfos[index],
+ defaultValueForParameter = defaultValue,
+ modifierList = modifierList
+ ).apply {
+ // a few last added parameters may be missing in newParameterValues
+ // because they have default values and we did not offer to enter value for them
+ if (newParameterValueIndex < newParameterValues.size) {
+ setNewParameterValue(newParameterValues[newParameterValueIndex++])
+ }
+ }
+ } else {
+ KotlinParameterInfo(
+ descriptor,
+ initialIndex,
+ parameter.name,
+ methodDescriptor.parameters[initialIndex].originalTypeInfo,
+ defaultValueForParameter = defaultValue,
+ modifierList = modifierList
+ ).apply {
+ currentTypeInfo = parameterTypeInfos[index]
+ }
+ }
+ parameters.add(parameterInfo)
+ }
+
+ val changeInfo = KotlinChangeInfo(
+ methodDescriptor,
+ context = declaration,
+ name = data.newSignature.name,
+ newReturnTypeInfo = returnTypeInfo,
+ parameterInfos = parameters,
+ receiver = receiver
+ )
+ val processor = KotlinChangeSignatureProcessor(project, changeInfo, "")
+ processor.run()
+ }
+
+ private fun KotlinParameterInfo.setNewParameterValue(value: NewParameterValue) {
+ when (value) {
+ is NewParameterValue.AnyVariable -> isUseAnySingleVariable = true
+ is NewParameterValue.Expression -> defaultValueForCall = value.expression as KtExpression
+ is NewParameterValue.None -> defaultValueForCall = null
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt
new file mode 100644
index 0000000..f919172
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt
@@ -0,0 +1,97 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.suggested.SuggestedRefactoringState
+import com.intellij.refactoring.suggested.SuggestedRefactoringStateChanges
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.children
+
+class KotlinSuggestedRefactoringStateChanges(refactoringSupport: SuggestedRefactoringSupport) :
+ SuggestedRefactoringStateChanges(refactoringSupport)
+{
+ override fun createInitialState(declaration: PsiElement): SuggestedRefactoringState? {
+ declaration as KtDeclaration
+ if (declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null // currently not supported
+ if (declaration.hasModifier(KtTokens.ACTUAL_KEYWORD)) return null // currently not supported
+ val state = super.createInitialState(declaration) ?: return null
+ if (isDuplicate(declaration, state.oldSignature)) return null
+ return state
+ }
+
+ private fun isDuplicate(declaration: KtDeclaration, signature: Signature): Boolean {
+ val container = declaration.parent as? KtDeclarationContainer ?: return false
+ if (container !is KtFile && container !is KtClassBody) return false
+ val name = declaration.name ?: return false
+ return when (declaration) {
+ is KtFunction -> {
+ container.declarations
+ .filter { it != declaration && it.name == name }
+ .any {
+ val otherSignature = signature(it, null) ?: return@any false
+ areDuplicateSignatures(otherSignature, signature)
+ }
+ }
+
+ is KtProperty -> {
+ container.declarations.any { it != declaration && it is KtProperty && it.name == name }
+ }
+
+ else -> false
+ }
+ }
+
+ // we can't compare signatures by equals here because it takes into account parameter id's and they will be different in our case
+ private fun areDuplicateSignatures(signature1: Signature, signature2: Signature): Boolean {
+ if (signature1.name != signature2.name) return false
+ if (signature1.type != signature2.type) return false
+ if (signature1.parameters.size != signature2.parameters.size) return false
+ return signature1.parameters.zip(signature2.parameters).all { (p1, p2) ->
+ p1.type == p2.type && p1.name == p2.name
+ }
+ }
+
+ override fun signature(declaration: PsiElement, prevState: SuggestedRefactoringState?): Signature? {
+ declaration as KtDeclaration
+ val name = declaration.name ?: return null
+ if (declaration !is KtCallableDeclaration || KotlinSuggestedRefactoringSupport.isOnlyRenameSupported(declaration)) {
+ return Signature.create(name, null, emptyList(), null)
+ }
+
+ val parameters = declaration.valueParameters.map { it.extractParameterData() ?: return null }
+ val type = declaration.typeReference?.text
+ val receiverType = declaration.receiverTypeReference?.text
+ val signature = Signature.create(
+ name,
+ type,
+ parameters,
+ KotlinSignatureAdditionalData(DeclarationType.fromDeclaration(declaration), receiverType)
+ ) ?: return null
+
+ return if (prevState == null) signature else matchParametersWithPrevState(signature, declaration, prevState)
+ }
+
+ override fun parameterMarkerRanges(declaration: PsiElement): List<TextRange?> {
+ if (declaration !is KtFunction) return emptyList()
+ return declaration.valueParameters.map { it.colon?.textRange }
+ }
+
+ private fun KtParameter.extractParameterData(): Parameter? {
+ val modifiers = modifierList?.node?.children()
+ ?.filter { it.elementType is KtModifierKeywordToken && it.text in modifiersToInclude }
+ ?.joinToString(separator = " ") { it.text } ?: ""
+ return Parameter(
+ Any(),
+ name ?: return null,
+ typeReference?.text ?: return null,
+ KotlinParameterAdditionalData(defaultValue?.text/*TODO: strip comments etc*/, modifiers)
+ )
+ }
+
+ private val modifiersToInclude = setOf(KtTokens.VARARG_KEYWORD.value)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt
new file mode 100644
index 0000000..94420d9
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt
@@ -0,0 +1,153 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
+
+class KotlinSuggestedRefactoringSupport : SuggestedRefactoringSupport {
+ override fun isDeclaration(psiElement: PsiElement): Boolean {
+ if (psiElement !is KtDeclaration) return false
+ if (psiElement is KtParameter && psiElement.ownerFunction != null) return false
+ return true
+ }
+
+ override fun signatureRange(declaration: PsiElement): TextRange? {
+ when (declaration) {
+ is KtPrimaryConstructor -> return declaration.textRange
+
+ is KtSecondaryConstructor -> return declaration.valueParameterList?.textRange
+
+ is KtCallableDeclaration -> {
+ if (isOnlyRenameSupported(declaration)) {
+ return declaration.nameIdentifier?.textRange
+ }
+
+ val start = declaration.receiverTypeReference?.textRange?.startOffset
+ ?: declaration.nameIdentifier?.textRange?.startOffset
+ ?: return null
+ val end = (declaration.typeReference ?: declaration.valueParameterList ?: declaration.nameIdentifier)
+ ?.textRange?.endOffset
+ ?: return null
+ return TextRange(start, end)
+ }
+
+ is KtNamedDeclaration -> return declaration.nameIdentifier?.textRange
+
+ else -> return null
+ }
+ }
+
+ override fun importsRange(psiFile: PsiFile): TextRange? {
+ return (psiFile as KtFile).importList?.textRange
+ }
+
+ override fun nameRange(declaration: PsiElement): TextRange? {
+ val identifier = when (declaration) {
+ is KtPrimaryConstructor -> declaration.containingClassOrObject?.nameIdentifier
+ is KtSecondaryConstructor -> declaration.getConstructorKeyword()
+ is KtNamedDeclaration -> declaration.nameIdentifier
+ else -> null
+ }
+ return identifier?.textRange
+ }
+
+ override fun hasSyntaxError(declaration: PsiElement): Boolean {
+ if (super.hasSyntaxError(declaration)) return true
+
+ // do not suggest renaming of local variable which has neither type nor initializer
+ // it's important because such variable declarations may appear on typing "val name = " before an expression
+ if (declaration is KtProperty && declaration.isLocal) {
+ if (declaration.typeReference == null && declaration.initializer == null) return true
+ }
+
+ return false
+ }
+
+ override fun isIdentifierStart(c: Char) = c.isJavaIdentifierStart()
+ override fun isIdentifierPart(c: Char) = c.isJavaIdentifierPart()
+
+ override val stateChanges = KotlinSuggestedRefactoringStateChanges(this)
+ override val availability = KotlinSuggestedRefactoringAvailability(this)
+ override val ui get() = KotlinSuggestedRefactoringUI
+ override val execution = KotlinSuggestedRefactoringExecution(this)
+
+ companion object {
+ fun isOnlyRenameSupported(declaration: KtCallableDeclaration): Boolean {
+ // for local variable - only rename
+ return declaration is KtVariableDeclaration && KtPsiUtil.isLocal(declaration)
+ }
+ }
+}
+
+enum class DeclarationType {
+ FUN {
+ override val prefixKeyword get() = "fun"
+ override val isFunction get() = true
+ },
+ VAL {
+ override val prefixKeyword get() = "val"
+ override val isFunction get() = false
+ },
+ VAR {
+ override val prefixKeyword get() = "var"
+ override val isFunction get() = false
+ },
+ PRIMARY_CONSTRUCTOR {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = true
+ },
+ SECONDARY_CONSTRUCTOR {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = true
+ },
+ OTHER {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = false
+ }
+
+ ;
+
+ abstract val prefixKeyword: String?
+ abstract val isFunction: Boolean
+
+ companion object {
+ fun fromDeclaration(declaration: KtDeclaration): DeclarationType = when (declaration) {
+ is KtPrimaryConstructor -> PRIMARY_CONSTRUCTOR
+
+ is KtSecondaryConstructor -> SECONDARY_CONSTRUCTOR
+
+ is KtNamedFunction -> FUN
+
+ is KtProperty -> if (declaration.isVar) VAR else VAL
+
+ else -> OTHER
+ }
+ }
+}
+
+internal data class KotlinSignatureAdditionalData(
+ val declarationType: DeclarationType,
+ val receiverType: String?
+) : SuggestedRefactoringSupport.SignatureAdditionalData
+
+internal data class KotlinParameterAdditionalData(
+ val defaultValue: String?,
+ val modifiers: String
+) : SuggestedRefactoringSupport.ParameterAdditionalData
+
+internal val Signature.receiverType: String?
+ get() = (additionalData as KotlinSignatureAdditionalData?)?.receiverType
+
+internal val Parameter.defaultValue: String?
+ get() = (additionalData as KotlinParameterAdditionalData?)?.defaultValue
+
+internal val Parameter.modifiers: String
+ get() = (additionalData as KotlinParameterAdditionalData?)?.modifiers ?: ""
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt
new file mode 100644
index 0000000..ab7141d
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt
@@ -0,0 +1,51 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.psi.PsiCodeFragment
+import com.intellij.refactoring.suggested.SuggestedChangeSignatureData
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution.NewParameterValue
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import com.intellij.refactoring.suggested.SuggestedRefactoringUI
+import com.intellij.refactoring.suggested.SignaturePresentationBuilder
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import org.jetbrains.kotlin.psi.KtExpressionCodeFragment
+import org.jetbrains.kotlin.psi.KtPsiFactory
+
+object KotlinSuggestedRefactoringUI : SuggestedRefactoringUI() {
+ override fun createSignaturePresentationBuilder(
+ signature: Signature,
+ otherSignature: Signature,
+ isOldSignature: Boolean
+ ): SignaturePresentationBuilder {
+ return KotlinSignaturePresentationBuilder(signature, otherSignature, isOldSignature)
+ }
+
+ override fun extractNewParameterData(data: SuggestedChangeSignatureData): List<NewParameterData> {
+ val result = mutableListOf<NewParameterData>()
+
+ val declaration = data.declaration
+ val factory = KtPsiFactory(declaration.project)
+
+ fun createCodeFragment() = factory.createExpressionCodeFragment("", declaration)
+
+ if (data.newSignature.receiverType != null && data.oldSignature.receiverType == null) {
+ result.add(NewParameterData("<receiver>", createCodeFragment(), false/*TODO*/))
+ }
+
+ fun isNewParameter(parameter: Parameter) = data.oldSignature.parameterById(parameter.id) == null
+
+ val newParameters = data.newSignature.parameters
+ val dropLastN = newParameters.reversed().count { isNewParameter(it) && it.defaultValue != null }
+ for (parameter in newParameters.dropLast(dropLastN)) {
+ if (isNewParameter(parameter)) {
+ result.add(NewParameterData(parameter.name, createCodeFragment(), false/*TODO*/))
+ }
+ }
+
+ return result
+ }
+
+ override fun extractValue(fragment: PsiCodeFragment): NewParameterValue.Expression? {
+ return (fragment as KtExpressionCodeFragment).getContentElement()
+ ?.let { NewParameterValue.Expression(it) }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt
index c93f6ab..75b404c 100644
--- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt
@@ -101,7 +101,7 @@
return null
}
- override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
+ override fun isIdentifierPart(file: PsiFile, text: CharSequence, offset: Int): Boolean {
val elementAtCaret = file.findElementAt(offset)
if (elementAtCaret?.node?.elementType == KtTokens.IDENTIFIER) return true
diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt.193 b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt.193
new file mode 100644
index 0000000..c93f6ab
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt.193
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.search.ideaExtensions
+
+import com.intellij.codeInsight.JavaTargetElementEvaluator
+import com.intellij.codeInsight.TargetElementEvaluatorEx
+import com.intellij.codeInsight.TargetElementUtil
+import com.intellij.codeInsight.TargetElementUtilExtender
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiReference
+import com.intellij.util.BitUtil
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.idea.intentions.isAutoCreatedItUsage
+import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
+import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
+import org.jetbrains.kotlin.idea.references.mainReference
+import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.*
+import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
+import org.jetbrains.kotlin.resolve.source.getPsi
+
+class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtilExtender {
+ companion object {
+ const val DO_NOT_UNWRAP_LABELED_EXPRESSION = 0x100
+ const val BYPASS_IMPORT_ALIAS = 0x200
+
+ // Place caret after the open curly brace in lambda for generated 'it'
+ fun findLambdaOpenLBraceForGeneratedIt(ref: PsiReference): PsiElement? {
+ val element: PsiElement = ref.element
+ if (element.text != "it") return null
+
+ if (element !is KtNameReferenceExpression || !isAutoCreatedItUsage(element)) return null
+
+ val itDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() ?: return null
+ val descriptorWithSource = itDescriptor.containingDeclaration as? DeclarationDescriptorWithSource ?: return null
+ val lambdaExpression = descriptorWithSource.source.getPsi()?.parent as? KtLambdaExpression ?: return null
+ return lambdaExpression.leftCurlyBrace.treeNext?.psi
+ }
+
+ // Navigate to receiver element for this in extension declaration
+ fun findReceiverForThisInExtensionFunction(ref: PsiReference): PsiElement? {
+ val element: PsiElement = ref.element
+ if (element.text != "this") return null
+
+ if (element !is KtNameReferenceExpression) return null
+ val callableDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() as? CallableDescriptor ?: return null
+
+ if (!callableDescriptor.isExtension) return null
+ val callableDeclaration = callableDescriptor.source.getPsi() as? KtCallableDeclaration ?: return null
+
+ return callableDeclaration.receiverTypeReference
+ }
+ }
+
+ override fun getAdditionalDefinitionSearchFlags() = 0
+
+ override fun getAdditionalReferenceSearchFlags() = DO_NOT_UNWRAP_LABELED_EXPRESSION or BYPASS_IMPORT_ALIAS
+
+ override fun getAllAdditionalFlags() = additionalDefinitionSearchFlags + additionalReferenceSearchFlags
+
+ override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is KtClass && element.isAbstract())
+
+ override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? {
+ if (ref is KtSimpleNameReference && ref.expression is KtLabelReferenceExpression) {
+ val refTarget = ref.resolve() as? KtExpression ?: return null
+ if (!BitUtil.isSet(flags, DO_NOT_UNWRAP_LABELED_EXPRESSION)) {
+ return refTarget.getLabeledParent(ref.expression.getReferencedName()) ?: refTarget
+ }
+ return refTarget
+ }
+
+ if (!BitUtil.isSet(flags, BYPASS_IMPORT_ALIAS)) {
+ (ref.element as? KtSimpleNameExpression)?.mainReference?.getImportAlias()?.let { return it }
+ }
+
+ // prefer destructing declaration entry to its target if element name is accepted
+ if (ref is KtDestructuringDeclarationReference && BitUtil.isSet(flags, TargetElementUtil.ELEMENT_NAME_ACCEPTED)) {
+ return ref.element
+ }
+
+ val refExpression = ref.element as? KtSimpleNameExpression
+ val calleeExpression = refExpression?.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
+ if (calleeExpression != null) {
+ (ref.resolve() as? KtConstructor<*>)?.let {
+ return if (flags and JavaTargetElementEvaluator().additionalReferenceSearchFlags != 0) it else it.containingClassOrObject
+ }
+ }
+
+ if (BitUtil.isSet(flags, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED)) {
+ return findLambdaOpenLBraceForGeneratedIt(ref)
+ ?: findReceiverForThisInExtensionFunction(ref)
+ }
+
+ return null
+ }
+
+ override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
+ val elementAtCaret = file.findElementAt(offset)
+
+ if (elementAtCaret?.node?.elementType == KtTokens.IDENTIFIER) return true
+ // '(' is considered identifier part if it belongs to primary constructor without 'constructor' keyword
+ return elementAtCaret?.getNonStrictParentOfType<KtPrimaryConstructor>()?.textOffset == offset
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt
index e4fcf5f..e4a87c4 100644
--- a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt
@@ -73,7 +73,7 @@
override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
if (usage is KotlinSliceUsage) return null
- return listOf(KotlinSliceUsage(usage.element, usage.parent, KotlinSliceAnalysisMode.Default, false))
+ return listOf(KotlinSliceUsage(usage.element ?: return null, usage.parent, KotlinSliceAnalysisMode.Default, false))
}
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt.193 b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt.193
new file mode 100644
index 0000000..e4fcf5f
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceProvider.kt.193
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.slicer
+
+import com.intellij.codeInsight.Nullability
+import com.intellij.ide.util.treeView.AbstractTreeStructure
+import com.intellij.openapi.actionSystem.DefaultActionGroup
+import com.intellij.psi.PsiElement
+import com.intellij.psi.util.parentOfType
+import com.intellij.slicer.*
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.references.KtReference
+import org.jetbrains.kotlin.idea.references.mainReference
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.isPlainWithEscapes
+import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
+import org.jetbrains.kotlin.psi2ir.deparenthesize
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.types.TypeUtils
+import org.jetbrains.kotlin.types.isError
+import org.jetbrains.kotlin.types.isNullabilityFlexible
+
+class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer {
+ companion object {
+ val LEAF_ELEMENT_EQUALITY = object : SliceLeafEquality() {
+ override fun substituteElement(element: PsiElement) = (element as? KtReference)?.resolve() ?: element
+ }
+ }
+
+ class KotlinGroupByNullnessAction(treeBuilder: SliceTreeBuilder) : GroupByNullnessActionBase(treeBuilder) {
+ override fun isAvailable() = true
+ }
+
+ val leafAnalyzer by lazy { SliceLeafAnalyzer(LEAF_ELEMENT_EQUALITY, this) }
+
+ val nullnessAnalyzer: HackedSliceNullnessAnalyzerBase by lazy {
+ object : HackedSliceNullnessAnalyzerBase(LEAF_ELEMENT_EQUALITY, this) {
+ override fun checkNullability(element: PsiElement?): Nullability {
+ val types = when (element) {
+ is KtCallableDeclaration -> listOfNotNull((element.resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType)
+ is KtDeclaration -> emptyList()
+ is KtExpression -> listOfNotNull(element.analyze(BodyResolveMode.PARTIAL).getType(element))
+ else -> emptyList()
+ }
+ return when {
+ types.isEmpty() -> return Nullability.UNKNOWN
+ types.all { KotlinBuiltIns.isNullableNothing(it) } -> Nullability.NULLABLE
+ types.any { it.isError || TypeUtils.isNullableType(it) || it.isNullabilityFlexible() } -> Nullability.UNKNOWN
+ else -> Nullability.NOT_NULL
+ }
+ }
+ }
+ }
+
+ override fun createRootUsage(element: PsiElement, params: SliceAnalysisParams) = KotlinSliceUsage(element, params)
+
+ override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
+ if (usage is KotlinSliceUsage) return null
+ return listOf(KotlinSliceUsage(usage.element, usage.parent, KotlinSliceAnalysisMode.Default, false))
+ }
+
+ override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
+ val element = atCaret.parentsWithSelf
+ .filterIsInstance<KtElement>()
+ .firstOrNull(::isSliceElement)
+ ?.deparenthesize() ?: return null
+
+ if (dataFlowToThis) {
+ if (element is KtConstantExpression) return null
+ if (element is KtStringTemplateExpression && element.isPlainWithEscapes()) return null
+ if (element is KtClassLiteralExpression) return null
+ if (element is KtCallableReferenceExpression) return null
+ }
+
+ return element
+ }
+
+ private fun isSliceElement(element: KtElement): Boolean {
+ return when {
+ element is KtProperty -> true
+ element is KtParameter -> true
+ element is KtDeclarationWithBody -> true
+ element is KtClass && !element.hasExplicitPrimaryConstructor() -> true
+ element is KtExpression && element !is KtDeclaration && element.parentOfType<KtTypeReference>() == null -> true
+ element is KtTypeReference && element == (element.parent as? KtCallableDeclaration)?.receiverTypeReference -> true
+ else -> false
+ }
+ }
+
+ override fun getElementForDescription(element: PsiElement): PsiElement {
+ return (element as? KtSimpleNameExpression)?.mainReference?.resolve() ?: element
+ }
+
+ override fun getRenderer() = KotlinSliceUsageCellRenderer
+
+ override fun startAnalyzeLeafValues(structure: AbstractTreeStructure, finalRunnable: Runnable) {
+ leafAnalyzer.startAnalyzeValues(structure, finalRunnable)
+ }
+
+ override fun startAnalyzeNullness(structure: AbstractTreeStructure, finalRunnable: Runnable) {
+ nullnessAnalyzer.startAnalyzeNullness(structure, finalRunnable)
+ }
+
+ override fun registerExtraPanelActions(group: DefaultActionGroup, builder: SliceTreeBuilder) {
+ if (builder.dataFlowToThis) {
+ group.add(GroupByLeavesAction(builder))
+ group.add(KotlinGroupByNullnessAction(builder))
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
index 219bb55..0739267 100644
--- a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
@@ -55,7 +55,7 @@
}
protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
- val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND)
+ val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND) ?: error("Can't find ToolWindowId.FIND")
val params = createParams(element)
val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193 b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193
new file mode 100644
index 0000000..219bb55
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.slicer
+
+import com.intellij.analysis.AnalysisScope
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindowId
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiElement
+import com.intellij.slicer.DuplicateMap
+import com.intellij.slicer.SliceAnalysisParams
+import com.intellij.slicer.SlicePanel
+import com.intellij.slicer.SliceRootNode
+import com.intellij.usageView.UsageInfo
+import com.intellij.usageView.UsageViewBundle
+import com.intellij.usages.PsiElementUsageTarget
+import com.intellij.usages.UsageContextPanel
+import com.intellij.usages.UsageView
+import com.intellij.usages.UsageViewPresentation
+import com.intellij.usages.impl.UsageContextPanelBase
+import com.intellij.usages.impl.UsageViewImpl
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.psi.KtDeclaration
+import java.awt.BorderLayout
+import javax.swing.JLabel
+import javax.swing.JPanel
+import javax.swing.SwingConstants
+
+sealed class KotlinUsageContextDataFlowPanelBase(
+ project: Project,
+ presentation: UsageViewPresentation,
+ private val isInflow: Boolean
+) : UsageContextPanelBase(project, presentation) {
+ private var panel: JPanel? = null
+
+ abstract class ProviderBase : UsageContextPanel.Provider {
+ override fun isAvailableFor(usageView: UsageView): Boolean {
+ val target = (usageView as UsageViewImpl).targets.firstOrNull() ?: return false
+ val element = (target as? PsiElementUsageTarget)?.element
+ return element is KtDeclaration && element.isValid
+ }
+ }
+
+ private fun createParams(element: PsiElement): SliceAnalysisParams {
+ return SliceAnalysisParams().apply {
+ scope = AnalysisScope(element.project)
+ dataFlowToThis = isInflow
+ showInstanceDereferences = true
+ }
+ }
+
+ protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
+ val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND)
+ val params = createParams(element)
+
+ val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
+
+ return object : SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
+ override fun isToShowAutoScrollButton() = false
+
+ override fun isToShowPreviewButton() = false
+
+ override fun isAutoScroll() = false
+
+ override fun setAutoScroll(autoScroll: Boolean) {}
+
+ override fun isPreview() = false
+
+ override fun setPreview(preview: Boolean) {}
+ }
+ }
+
+ public override fun updateLayoutLater(infos: List<UsageInfo>?) {
+ if (infos == null) {
+ removeAll()
+ val title = UsageViewBundle.message("select.the.usage.to.preview", myPresentation.usagesWord)
+ add(JLabel(title, SwingConstants.CENTER), BorderLayout.CENTER)
+ } else {
+ val element = infos.firstOrNull()?.element ?: return
+ if (panel != null) {
+ Disposer.dispose(panel as Disposable)
+ }
+
+ val panel = createPanel(element, isInflow)
+ Disposer.register(this, panel as Disposable)
+ removeAll()
+ add(panel, BorderLayout.CENTER)
+ this.panel = panel
+ }
+ revalidate()
+ }
+
+ override fun dispose() {
+ super.dispose()
+ panel = null
+ }
+}
+
+class KotlinUsageContextDataInflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, true) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataInflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = KotlinBundle.message("slicer.title.dataflow.to.here")
+ }
+}
+
+class KotlinUsageContextDataOutflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, false) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataOutflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = KotlinBundle.message("slicer.title.dataflow.from.here")
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt b/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt
index ba5a504..391616a 100644
--- a/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt
@@ -5,9 +5,28 @@
package org.jetbrains.kotlin.idea
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
+import com.intellij.openapi.application.ModalityState
+import com.intellij.openapi.application.ReadAction.nonBlocking
import com.intellij.openapi.project.Project
+import com.intellij.psi.search.FileTypeIndex
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.util.concurrency.AppExecutorUtil
+import java.util.concurrent.Callable
-// FIX ME WHEN BUNCH 193 REMOVED
+// FIX ME WHEN BUNCH 201 REMOVED
+
fun runActivity(project: Project) {
- // nothing for 193
+ nonBlocking(Callable {
+ return@Callable FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, GlobalSearchScope.projectScope(project))
+ })
+ .inSmartMode(project)
+ .expireWith(project)
+ .finishOnUiThread(ModalityState.any()) { hasKotlinFiles ->
+ if (!hasKotlinFiles) return@finishOnUiThread
+
+ val daemonCodeAnalyzer = DaemonCodeAnalyzerImpl.getInstanceEx(project) as DaemonCodeAnalyzerImpl
+ daemonCodeAnalyzer.runLocalInspectionPassAfterCompletionOfGeneralHighlightPass(true)
+ }
+ .submit(AppExecutorUtil.getAppExecutorService())
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt.193
new file mode 100644
index 0000000..ba5a504
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/startupCompat.kt.193
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea
+
+import com.intellij.openapi.project.Project
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun runActivity(project: Project) {
+ // nothing for 193
+}
\ No newline at end of file
diff --git a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt
old mode 100755
new mode 100644
index 6294481..7fb60e2
--- a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt
+++ b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt
@@ -1,11 +1,11 @@
import org.junit.Test
-class <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest\"">MyKotlinTest</lineMarker> {
+class <lineMarker descr="Run Test" settings=":test --tests \"MyKotlinTest\"">MyKotlinTest</lineMarker> {
@Test
- fun <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest.testA\"">testA</lineMarker>() {
+ fun <lineMarker descr="Run Test" settings=":test --tests \"MyKotlinTest.testA\"">testA</lineMarker>() {
}
@Test
- fun <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest.testB\"">testB</lineMarker>() {
+ fun <lineMarker descr="Run Test" settings=":test --tests \"MyKotlinTest.testB\"">testB</lineMarker>() {
}
}
\ No newline at end of file
diff --git a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt.193 b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt.193
new file mode 100644
index 0000000..6294481
--- /dev/null
+++ b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt.193
@@ -0,0 +1,11 @@
+import org.junit.Test
+
+class <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest\"">MyKotlinTest</lineMarker> {
+ @Test
+ fun <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest.testA\"">testA</lineMarker>() {
+ }
+
+ @Test
+ fun <lineMarker descr="Run Test" settings=":cleanTest :test --tests \"MyKotlinTest.testB\"">testB</lineMarker>() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/navigationToolbar/ClassProperty.kt b/idea/testData/navigationToolbar/ClassProperty.kt
index 4a43c81..9c21c98 100644
--- a/idea/testData/navigationToolbar/ClassProperty.kt
+++ b/idea/testData/navigationToolbar/ClassProperty.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, ClassProperty
+// NAV_BAR_ITEMS: src, ClassProperty, foo: Int
class ClassProperty {
val foo: Int
diff --git a/idea/testData/navigationToolbar/ClassProperty.kt.193 b/idea/testData/navigationToolbar/ClassProperty.kt.193
new file mode 100644
index 0000000..4a43c81
--- /dev/null
+++ b/idea/testData/navigationToolbar/ClassProperty.kt.193
@@ -0,0 +1,8 @@
+// NAV_BAR_ITEMS: src, ClassProperty
+
+class ClassProperty {
+ val foo: Int
+ get() {
+ return 42<caret>
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/navigationToolbar/MethodInClass.kt b/idea/testData/navigationToolbar/MethodInClass.kt
index 48d1742..c752419 100644
--- a/idea/testData/navigationToolbar/MethodInClass.kt
+++ b/idea/testData/navigationToolbar/MethodInClass.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, MethodInClass
+// NAV_BAR_ITEMS: src, MethodInClass, foo()
class MethodInClass {
fun foo() { <caret> }
diff --git a/idea/testData/navigationToolbar/MethodInClass.kt.193 b/idea/testData/navigationToolbar/MethodInClass.kt.193
new file mode 100644
index 0000000..48d1742
--- /dev/null
+++ b/idea/testData/navigationToolbar/MethodInClass.kt.193
@@ -0,0 +1,5 @@
+// NAV_BAR_ITEMS: src, MethodInClass
+
+class MethodInClass {
+ fun foo() { <caret> }
+}
\ No newline at end of file
diff --git a/idea/testData/navigationToolbar/SeveralClassesInFile.kt b/idea/testData/navigationToolbar/SeveralClassesInFile.kt
index 513cc5c..38f65c1 100644
--- a/idea/testData/navigationToolbar/SeveralClassesInFile.kt
+++ b/idea/testData/navigationToolbar/SeveralClassesInFile.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, SeveralClassesInFile.kt
+// NAV_BAR_ITEMS: src, SeveralClassesInFile.kt, SeveralClassesInFile
class Foo {
diff --git a/idea/testData/navigationToolbar/SeveralClassesInFile.kt.193 b/idea/testData/navigationToolbar/SeveralClassesInFile.kt.193
new file mode 100644
index 0000000..513cc5c
--- /dev/null
+++ b/idea/testData/navigationToolbar/SeveralClassesInFile.kt.193
@@ -0,0 +1,13 @@
+// NAV_BAR_ITEMS: src, SeveralClassesInFile.kt
+
+class Foo {
+
+}
+
+class SeveralClassesInFile {
+ <caret>
+}
+
+fun method() {
+
+}
diff --git a/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt b/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt
index 972955a..d408983 100644
--- a/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt
+++ b/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, fileNameDoesntMatchClassName.kt
+// NAV_BAR_ITEMS: src, fileNameDoesntMatchClassName.kt, Foo, bar()
class Foo {
fun bar() { <caret> }
diff --git a/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt.193 b/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt.193
new file mode 100644
index 0000000..972955a
--- /dev/null
+++ b/idea/testData/navigationToolbar/fileNameDoesntMatchClassName.kt.193
@@ -0,0 +1,5 @@
+// NAV_BAR_ITEMS: src, fileNameDoesntMatchClassName.kt
+
+class Foo {
+ fun bar() { <caret> }
+}
diff --git a/idea/testData/navigationToolbar/topLevelFunction.kt b/idea/testData/navigationToolbar/topLevelFunction.kt
index 0694a9a..1db12d6 100644
--- a/idea/testData/navigationToolbar/topLevelFunction.kt
+++ b/idea/testData/navigationToolbar/topLevelFunction.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, topLevelFunction.kt
+// NAV_BAR_ITEMS: src, topLevelFunction.kt, foo()
fun foo() {
val bar = <caret>"string"
diff --git a/idea/testData/navigationToolbar/topLevelFunction.kt.193 b/idea/testData/navigationToolbar/topLevelFunction.kt.193
new file mode 100644
index 0000000..0694a9a
--- /dev/null
+++ b/idea/testData/navigationToolbar/topLevelFunction.kt.193
@@ -0,0 +1,9 @@
+// NAV_BAR_ITEMS: src, topLevelFunction.kt
+
+fun foo() {
+ val bar = <caret>"string"
+}
+
+class SomeClass {
+
+}
diff --git a/idea/testData/navigationToolbar/topLevelProperty.kt b/idea/testData/navigationToolbar/topLevelProperty.kt
index 055c49a..a2b73b3 100644
--- a/idea/testData/navigationToolbar/topLevelProperty.kt
+++ b/idea/testData/navigationToolbar/topLevelProperty.kt
@@ -1,4 +1,4 @@
-// NAV_BAR_ITEMS: src, topLevelProperty.kt
+// NAV_BAR_ITEMS: src, topLevelProperty.kt, foo: Int
val foo: Int
get() {
diff --git a/idea/testData/navigationToolbar/topLevelProperty.kt.193 b/idea/testData/navigationToolbar/topLevelProperty.kt.193
new file mode 100644
index 0000000..055c49a
--- /dev/null
+++ b/idea/testData/navigationToolbar/topLevelProperty.kt.193
@@ -0,0 +1,6 @@
+// NAV_BAR_ITEMS: src, topLevelProperty.kt
+
+val foo: Int
+ get() {
+ return 1<caret>
+ }
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt
index d1a9d5d..de4724e2 100644
--- a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt
@@ -1,5 +1,7 @@
package a
+import b.X as XX
+
fun bar() {
- val t: b.X = b.X()
+ val t: XX = XX()
}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt.193 b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt.193
new file mode 100644
index 0000000..d1a9d5d
--- /dev/null
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/a/specificImport.kt.193
@@ -0,0 +1,5 @@
+package a
+
+fun bar() {
+ val t: b.X = b.X()
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt
index 20a79ef..c7894ca 100644
--- a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt
@@ -1,5 +1,7 @@
package b
+import b.X as XX
+
fun bar() {
- val t: b.X = b.X()
+ val t: XX = XX()
}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt.193 b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt.193
new file mode 100644
index 0000000..20a79ef
--- /dev/null
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInAnotherPackage/after/b/specificImport.kt.193
@@ -0,0 +1,5 @@
+package b
+
+fun bar() {
+ val t: b.X = b.X()
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt
index c097f16..a1a29b3 100644
--- a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt
@@ -1,5 +1,7 @@
package a
+import a.X as XX
+
fun bar(s: String) {
- val t: a.X = a.X()
+ val t: XX = XX()
}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt.193 b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt.193
new file mode 100644
index 0000000..c097f16
--- /dev/null
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackage/after/a/specificImport.kt.193
@@ -0,0 +1,5 @@
+package a
+
+fun bar(s: String) {
+ val t: a.X = a.X()
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt
index 6ed96e3..970ea3c 100644
--- a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt
@@ -1,5 +1,7 @@
package a
+import a.Y as XX
+
fun bar(s: String) {
- val t: a.Y = a.Y()
+ val t: XX = XX()
}
\ No newline at end of file
diff --git a/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt.193 b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt.193
new file mode 100644
index 0000000..6ed96e3
--- /dev/null
+++ b/idea/testData/refactoring/move/java/moveClass/moveInnerToTop/moveNestedClassToTopLevelInTheSamePackageAndRename/after/a/specificImport.kt.193
@@ -0,0 +1,5 @@
+package a
+
+fun bar(s: String) {
+ val t: a.Y = a.Y()
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt b/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt
index 08d9f4b..af83951 100644
--- a/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt
+++ b/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt
@@ -7,5 +7,5 @@
import com.intellij.util.Processor
-// FIX ME WHEN BUNCH 193 REMOVED
-typealias ProcessorInCompat<T> = Processor<T>
\ No newline at end of file
+// FIX ME WHEN BUNCH 201 REMOVED
+typealias ProcessorInCompat<T> = Processor<in T>
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt.193 b/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt.193
new file mode 100644
index 0000000..08d9f4b
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/findUsages/customUsageSearcher.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.findUsages
+
+import com.intellij.util.Processor
+
+// FIX ME WHEN BUNCH 193 REMOVED
+typealias ProcessorInCompat<T> = Processor<T>
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
index 26fe638..14a1098 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
@@ -48,7 +48,7 @@
with(element) {
try {
- Assert.assertEquals("Number of methods has changed. Please update test.", 55, PsiElement::class.java.methods.size)
+ Assert.assertEquals("Number of methods has changed. Please update test.", 56, PsiElement::class.java.methods.size)
project
Assert.assertTrue(language == KotlinLanguage.INSTANCE)
@@ -95,6 +95,7 @@
Assert.assertTrue(isValid)
isWritable
+ @Suppress("UnstableApiUsage") ownReferences
reference
references
putCopyableUserData(TEST_DATA_KEY, 12)
diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193
new file mode 100644
index 0000000..26fe638
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.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.", 55, PsiElement::class.java.methods.size)
+
+ project
+ Assert.assertTrue(language == KotlinLanguage.INSTANCE)
+ manager
+ children
+ parent
+ firstChild
+ lastChild
+ nextSibling
+ prevSibling
+ containingFile
+ textRange
+ //textRangeInParent - throws an exception for non-physical elements, it is expected behaviour
+ 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)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt
index 658aedc..e766ab1 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt
@@ -12,6 +12,7 @@
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiFile
import com.intellij.rt.execution.junit.FileComparisonFailure
import com.intellij.testFramework.ExpectedHighlightingData
import com.intellij.testFramework.LightProjectDescriptor
@@ -40,14 +41,14 @@
fun doTest(path: String) = doTest(path) {}
protected fun doAndCheckHighlighting(
- project: Project,
+ psiFile: PsiFile,
documentToAnalyze: Document,
expectedHighlighting: ExpectedHighlightingData,
expectedFile: File
): List<LineMarkerInfo<*>> {
myFixture.doHighlighting()
- return checkHighlighting(project, documentToAnalyze, expectedHighlighting, expectedFile)
+ return checkHighlighting(psiFile, documentToAnalyze, expectedHighlighting, expectedFile)
}
fun doTest(path: String, additionalCheck: () -> Unit) {
@@ -62,12 +63,12 @@
val project = myFixture.project
val document = myFixture.editor.document
- val data = ExpectedHighlightingData(document, false, false, false, myFixture.file)
+ val data = ExpectedHighlightingData(document, false, false, false)
data.init()
PsiDocumentManager.getInstance(project).commitAllDocuments()
- val markers = doAndCheckHighlighting(myFixture.project, document, data, testDataFile())
+ val markers = doAndCheckHighlighting(myFixture.file, document, data, testDataFile())
assertNavigationElements(myFixture.project, myFixture.file as KtFile, markers)
additionalCheck()
@@ -150,15 +151,15 @@
}
fun checkHighlighting(
- project: Project,
+ psiFile: PsiFile,
documentToAnalyze: Document,
expectedHighlighting: ExpectedHighlightingData,
expectedFile: File
): MutableList<LineMarkerInfo<*>> {
- val markers = DaemonCodeAnalyzerImpl.getLineMarkers(documentToAnalyze, project)
+ val markers = DaemonCodeAnalyzerImpl.getLineMarkers(documentToAnalyze, psiFile.project)
try {
- expectedHighlighting.checkLineMarkers(markers, documentToAnalyze.text)
+ expectedHighlighting.checkLineMarkers(psiFile, markers, documentToAnalyze.text)
// This is a workaround for sad bug in ExpectedHighlightingData:
// the latter doesn't throw assertion error when some line markers are expected, but none are present.
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt.193
new file mode 100644
index 0000000..658aedc
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt.193
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.codeInsight
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings
+import com.intellij.codeInsight.daemon.LineMarkerInfo
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.rt.execution.junit.FileComparisonFailure
+import com.intellij.testFramework.ExpectedHighlightingData
+import com.intellij.testFramework.LightProjectDescriptor
+import com.intellij.testFramework.PlatformTestUtil
+import com.intellij.testFramework.UsefulTestCase
+import junit.framework.TestCase
+import org.jetbrains.kotlin.idea.highlighter.markers.TestableLineMarkerNavigator
+import org.jetbrains.kotlin.idea.navigation.NavigationTestUtils
+import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
+import org.jetbrains.kotlin.test.KotlinTestUtils
+import org.jetbrains.kotlin.test.TagsTestDataUtil
+import org.jetbrains.kotlin.test.util.renderAsGotoImplementation
+import org.junit.Assert
+import java.io.File
+
+abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase() {
+
+ override fun getProjectDescriptor(): LightProjectDescriptor {
+ return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+ }
+
+ fun doTest(path: String) = doTest(path) {}
+
+ protected fun doAndCheckHighlighting(
+ project: Project,
+ documentToAnalyze: Document,
+ expectedHighlighting: ExpectedHighlightingData,
+ expectedFile: File
+ ): List<LineMarkerInfo<*>> {
+ myFixture.doHighlighting()
+
+ return checkHighlighting(project, documentToAnalyze, expectedHighlighting, expectedFile)
+ }
+
+ fun doTest(path: String, additionalCheck: () -> Unit) {
+ val fileText = FileUtil.loadFile(testDataFile())
+ try {
+ ConfigLibraryUtil.configureLibrariesByDirective(myFixture.module, PlatformTestUtil.getCommunityPath(), fileText)
+ if (InTextDirectivesUtils.findStringWithPrefixes(fileText, "METHOD_SEPARATORS") != null) {
+ DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS = true
+ }
+
+ myFixture.configureByFile(fileName())
+ val project = myFixture.project
+ val document = myFixture.editor.document
+
+ val data = ExpectedHighlightingData(document, false, false, false, myFixture.file)
+ data.init()
+
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+
+ val markers = doAndCheckHighlighting(myFixture.project, document, data, testDataFile())
+
+ assertNavigationElements(myFixture.project, myFixture.file as KtFile, markers)
+ additionalCheck()
+ } catch (exc: Exception) {
+ throw RuntimeException(exc)
+ } finally {
+ ConfigLibraryUtil.unconfigureLibrariesByDirective(module, fileText)
+ DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS = false
+ }
+
+ }
+
+ companion object {
+
+ @Suppress("SpellCheckingInspection")
+ private const val LINE_MARKER_PREFIX = "LINEMARKER:"
+ private const val TARGETS_PREFIX = "TARGETS"
+
+ fun assertNavigationElements(project: Project, file: KtFile, markers: List<LineMarkerInfo<*>>) {
+ val navigationDataComments = KotlinTestUtils.getLastCommentsInFile(
+ file, KotlinTestUtils.CommentType.BLOCK_COMMENT, false
+ )
+ if (navigationDataComments.isEmpty()) return
+
+ for ((navigationCommentIndex, navigationComment) in navigationDataComments.reversed().withIndex()) {
+ val description = getLineMarkerDescription(navigationComment)
+ val navigateMarkers = markers.filter { it.lineMarkerTooltip?.startsWith(description) == true }
+ val navigateMarker = navigateMarkers.singleOrNull() ?: navigateMarkers.getOrNull(navigationCommentIndex)
+
+ TestCase.assertNotNull(
+ String.format("Can't find marker for navigation check with description \"%s\"", description),
+ navigateMarker
+ )
+
+ val handler = navigateMarker!!.navigationHandler
+ if (handler is TestableLineMarkerNavigator) {
+ val navigateElements = handler.getTargetsPopupDescriptor(navigateMarker.element)?.targets?.sortedBy {
+ it.renderAsGotoImplementation()
+ }
+ val actualNavigationData = NavigationTestUtils.getNavigateElementsText(project, navigateElements)
+
+ UsefulTestCase.assertSameLines(getExpectedNavigationText(navigationComment), actualNavigationData)
+ } else {
+ Assert.fail("Only TestableLineMarkerNavigator are supported in navigate check")
+ }
+ }
+ }
+
+ private fun getLineMarkerDescription(navigationComment: String): String {
+ val firstLineEnd = navigationComment.indexOf("\n")
+ TestCase.assertTrue(
+ "The first line in block comment must contain description of marker for navigation check", firstLineEnd != -1
+ )
+
+ var navigationMarkerText = navigationComment.substring(0, firstLineEnd)
+
+ TestCase.assertTrue(
+ String.format("Add %s directive in first line of comment", LINE_MARKER_PREFIX),
+ navigationMarkerText.startsWith(LINE_MARKER_PREFIX)
+ )
+
+ navigationMarkerText = navigationMarkerText.substring(LINE_MARKER_PREFIX.length)
+
+ return navigationMarkerText.trim { it <= ' ' }
+ }
+
+ private fun getExpectedNavigationText(navigationComment: String): String {
+ val firstLineEnd = navigationComment.indexOf("\n")
+
+ var expectedNavigationText = navigationComment.substring(firstLineEnd + 1)
+
+ TestCase.assertTrue(
+ String.format("Marker %s is expected before navigation data", TARGETS_PREFIX),
+ expectedNavigationText.startsWith(TARGETS_PREFIX)
+ )
+
+ expectedNavigationText = expectedNavigationText.substring(expectedNavigationText.indexOf("\n") + 1)
+
+ return expectedNavigationText
+ }
+
+ fun checkHighlighting(
+ project: Project,
+ documentToAnalyze: Document,
+ expectedHighlighting: ExpectedHighlightingData,
+ expectedFile: File
+ ): MutableList<LineMarkerInfo<*>> {
+ val markers = DaemonCodeAnalyzerImpl.getLineMarkers(documentToAnalyze, project)
+
+ try {
+ expectedHighlighting.checkLineMarkers(markers, documentToAnalyze.text)
+
+ // This is a workaround for sad bug in ExpectedHighlightingData:
+ // the latter doesn't throw assertion error when some line markers are expected, but none are present.
+ if (FileUtil.loadFile(expectedFile).contains("<lineMarker") && markers.isEmpty()) {
+ throw AssertionError("Some line markers are expected, but nothing is present at all")
+ }
+ } catch (error: AssertionError) {
+ try {
+ val actualTextWithTestData = TagsTestDataUtil.insertInfoTags(markers, true, documentToAnalyze.text)
+ KotlinTestUtils.assertEqualsToFile(expectedFile, actualTextWithTestData)
+ } catch (failure: FileComparisonFailure) {
+ throw FileComparisonFailure(
+ error.message + "\n" + failure.message,
+ failure.expected,
+ failure.actual,
+ failure.filePath
+ )
+ }
+ }
+ return markers
+ }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt
index d6c95ea..c0e0a2e 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt
@@ -65,9 +65,7 @@
val project = myFixture.project
for (file in libraryOriginal.walkTopDown().filter { !it.isDirectory }) {
myFixture.openFileInEditor(fileSystem.findFileByPath(file.absolutePath)!!)
- val data = ExpectedHighlightingData(
- myFixture.editor.document, false, false, false, myFixture.file
- )
+ val data = ExpectedHighlightingData(myFixture.editor.document, false, false, false)
data.init()
val librarySourceFile = libraryClean!!.resolve(file.relativeTo(libraryOriginal).path)
@@ -79,7 +77,7 @@
throw AssertionError("File ${myFixture.file.virtualFile.path} should be in library sources!")
}
- doAndCheckHighlighting(myFixture.project, document, data, file)
+ doAndCheckHighlighting(myFixture.file, document, data, file)
}
}
}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt.193
new file mode 100644
index 0000000..d6c95ea
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTestInLibrarySources.kt.193
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.codeInsight
+
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.roots.ModifiableRootModel
+import com.intellij.openapi.roots.OrderRootType
+import com.intellij.openapi.vfs.LocalFileSystem
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.testFramework.ExpectedHighlightingData
+import com.intellij.util.io.createFile
+import com.intellij.util.io.write
+import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
+import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
+import org.jetbrains.kotlin.idea.test.SdkAndMockLibraryProjectDescriptor
+import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
+import java.io.File
+import java.nio.file.Files
+
+abstract class AbstractLineMarkersTestInLibrarySources : AbstractLineMarkersTest() {
+
+ private var libraryCleanPath: String? = null
+
+ private var libraryClean: File? = null
+
+ private fun getLibraryCleanPath(): String = libraryCleanPath!!
+
+ private fun getLibraryOriginalPath(): String = PluginTestCaseBase.getTestDataPathBase() + "/codeInsightInLibrary/_library"
+
+ override fun getProjectDescriptor(): SdkAndMockLibraryProjectDescriptor {
+ if (libraryCleanPath == null) {
+ val libraryClean = Files.createTempDirectory("lineMarkers_library")
+ val libraryOriginal = File(getLibraryOriginalPath())
+ libraryCleanPath = libraryClean.toString()
+
+ for (file in libraryOriginal.walkTopDown().filter { !it.isDirectory }) {
+ val text = file.readText().replace("</?lineMarker.*?>".toRegex(), "")
+ val cleanFile = libraryClean.resolve(file.relativeTo(libraryOriginal).path)
+ cleanFile.createFile()
+ cleanFile.write(text)
+ }
+ this.libraryClean = File(libraryCleanPath)
+ }
+ return object : SdkAndMockLibraryProjectDescriptor(getLibraryCleanPath(), false) {
+ override fun configureModule(module: Module, model: ModifiableRootModel) {
+ super.configureModule(module, model)
+
+ val library = model.moduleLibraryTable.getLibraryByName(LIBRARY_NAME)!!
+ val modifiableModel = library.modifiableModel
+
+ modifiableModel.addRoot(LocalFileSystem.getInstance().findFileByIoFile(libraryClean!!)!!, OrderRootType.SOURCES)
+ modifiableModel.commit()
+ }
+ }
+ }
+
+ fun doTestWithLibrary(path: String) {
+ doTest(path) {
+ val fileSystem = VirtualFileManager.getInstance().getFileSystem("file")
+ val libraryOriginal = File(getLibraryOriginalPath())
+ val project = myFixture.project
+ for (file in libraryOriginal.walkTopDown().filter { !it.isDirectory }) {
+ myFixture.openFileInEditor(fileSystem.findFileByPath(file.absolutePath)!!)
+ val data = ExpectedHighlightingData(
+ myFixture.editor.document, false, false, false, myFixture.file
+ )
+ data.init()
+
+ val librarySourceFile = libraryClean!!.resolve(file.relativeTo(libraryOriginal).path)
+ myFixture.openFileInEditor(fileSystem.findFileByPath(librarySourceFile.absolutePath)!!)
+ val document = myFixture.editor.document
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+
+ if (!ProjectRootsUtil.isLibrarySourceFile(project, myFixture.file.virtualFile)) {
+ throw AssertionError("File ${myFixture.file.virtualFile.path} should be in library sources!")
+ }
+
+ doAndCheckHighlighting(myFixture.project, document, data, file)
+ }
+ }
+ }
+
+ override fun tearDown() {
+ libraryClean?.deleteRecursively()
+ ConfigLibraryUtil.removeLibrary(module, SdkAndMockLibraryProjectDescriptor.LIBRARY_NAME)
+
+ super.tearDown()
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt
index 865bde9..8b029f4 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt
@@ -5,9 +5,32 @@
package org.jetbrains.kotlin.idea.codeInsight
+import com.intellij.testFramework.UsefulTestCase
+import org.jetbrains.kotlin.idea.KotlinDocumentationProvider
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
//BUNCH 201
abstract class AbstractRenderingKDocTest : KotlinLightCodeInsightFixtureTestCase() {
- protected fun doTest(path: String) = Unit
+
+ override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ protected fun doTest(path: String) {
+ myFixture.configureByFile(fileName())
+ val file = myFixture.file
+
+ val kDocProvider = KotlinDocumentationProvider()
+
+ val comments = mutableListOf<String>()
+ kDocProvider.collectDocComments(file) {
+ val rendered = it.owner?.let { owner -> kDocProvider.generateRenderedDoc(owner) }
+ if (rendered != null) {
+ comments.add(rendered.replace("\n", ""))
+ }
+ }
+
+ val expectedRenders = InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, "// RENDER: ")
+ UsefulTestCase.assertOrderedEquals(comments, expectedRenders)
+ }
}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.193
new file mode 100644
index 0000000..865bde9
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.193
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.codeInsight
+
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+
+//BUNCH 201
+abstract class AbstractRenderingKDocTest : KotlinLightCodeInsightFixtureTestCase() {
+ protected fun doTest(path: String) = Unit
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt
index af60955..bebbeeb 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt
@@ -24,7 +24,7 @@
protected fun doTest(unused: String) {
myFixture.configureByFile(fileName())
val document = myFixture.editor.document
- val data = ExpectedHighlightingData(document, false, false, true, false, myFixture.file)
+ val data = ExpectedHighlightingData(document, false, false, true, false)
data.init()
val caret = document.extractMarkerOffset(project, CARET_TAG)
@@ -48,7 +48,7 @@
.create()
}
- data.checkResult(infos, StringBuilder(document.text).insert(caret, CARET_TAG).toString())
+ data.checkResult(myFixture.file, infos, StringBuilder(document.text).insert(caret, CARET_TAG).toString())
}
private fun isUsageHighlighting(info: RangeHighlighter): Boolean {
diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt.193
new file mode 100644
index 0000000..af60955
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractUsageHighlightingTest.kt.193
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter
+
+import com.intellij.codeInsight.daemon.impl.HighlightInfo
+import com.intellij.codeInsight.daemon.impl.HighlightInfoType
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandler
+import com.intellij.openapi.editor.colors.EditorColors
+import com.intellij.openapi.editor.colors.EditorColorsManager
+import com.intellij.openapi.editor.markup.RangeHighlighter
+import com.intellij.openapi.editor.markup.TextAttributes
+import com.intellij.testFramework.ExpectedHighlightingData
+import org.jetbrains.kotlin.idea.test.*
+
+abstract class AbstractUsageHighlightingTest : KotlinLightCodeInsightFixtureTestCase() {
+ companion object {
+ // Not standard <caret> to leave it in text after configureByFile and remove manually after collecting highlighting information
+ const val CARET_TAG = "~"
+ }
+
+ protected fun doTest(unused: String) {
+ myFixture.configureByFile(fileName())
+ val document = myFixture.editor.document
+ val data = ExpectedHighlightingData(document, false, false, true, false, myFixture.file)
+ data.init()
+
+ val caret = document.extractMarkerOffset(project, CARET_TAG)
+ assert(caret != -1) { "Caret marker '$CARET_TAG' expected" }
+ editor.caretModel.moveToOffset(caret)
+
+ HighlightUsagesHandler.invoke(project, editor, myFixture.file)
+ val highlighters = myFixture.editor.markupModel.allHighlighters
+
+ val infos = highlighters
+ .filter { isUsageHighlighting(it) }
+ .map { highlighter ->
+ var startOffset = highlighter.startOffset
+ var endOffset = highlighter.endOffset
+
+ if (startOffset > caret) startOffset += CARET_TAG.length
+ if (endOffset > caret) endOffset += CARET_TAG.length
+
+ HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION)
+ .range(startOffset, endOffset)
+ .create()
+ }
+
+ data.checkResult(infos, StringBuilder(document.text).insert(caret, CARET_TAG).toString())
+ }
+
+ private fun isUsageHighlighting(info: RangeHighlighter): Boolean {
+ val globalScheme = EditorColorsManager.getInstance().globalScheme
+
+ val readAttributes: TextAttributes =
+ globalScheme.getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES)
+ val writeAttributes: TextAttributes =
+ globalScheme.getAttributes(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES)
+
+ return info.textAttributes == readAttributes || info.textAttributes == writeAttributes
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt
index 27f4b2a..9b854a3 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt
@@ -53,7 +53,7 @@
private fun loadKotlinInspections(): List<InspectionToolWrapper<InspectionProfileEntry, InspectionEP>> {
return InspectionToolRegistrar.getInstance().createTools().filter {
it.extension.pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID
- }
+ } as List<InspectionToolWrapper<InspectionProfileEntry, InspectionEP>>
}
private fun loadKotlinInspectionExtensions() =
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt.193
new file mode 100644
index 0000000..27f4b2a
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/InspectionDescriptionTest.kt.193
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.inspections
+
+import com.intellij.codeInspection.InspectionEP
+import com.intellij.codeInspection.InspectionProfileEntry
+import com.intellij.codeInspection.LocalInspectionEP
+import com.intellij.codeInspection.LocalInspectionTool
+import com.intellij.codeInspection.ex.InspectionToolRegistrar
+import com.intellij.codeInspection.ex.InspectionToolWrapper
+import com.intellij.openapi.extensions.Extensions
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.testFramework.LightPlatformTestCase
+import com.intellij.testFramework.UsefulTestCase
+import gnu.trove.THashMap
+import org.jetbrains.kotlin.idea.KotlinPluginUtil
+import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
+import org.junit.runner.RunWith
+
+@RunWith(JUnit3WithIdeaConfigurationRunner::class)
+class InspectionDescriptionTest : LightPlatformTestCase() {
+
+ fun testDescriptionsAndShortNames() {
+ val shortNames = THashMap<String, InspectionToolWrapper<InspectionProfileEntry, InspectionEP>>()
+
+ val inspectionTools = loadKotlinInspections()
+ val errors = StringBuilder()
+ for (toolWrapper in inspectionTools) {
+ val description = toolWrapper.loadDescription()
+
+ if (description == null) {
+ errors.append("description is null for inspection '").append(desc(toolWrapper))
+ }
+
+ val shortName = toolWrapper.shortName
+ val tool = shortNames[shortName]
+ if (tool != null) {
+ errors.append(
+ "Short names must be unique: " + shortName + "\n" +
+ "inspection: '" + desc(tool) + "\n" +
+ " and '" + desc(toolWrapper)
+ )
+ }
+ shortNames.put(shortName, toolWrapper)
+ }
+
+ UsefulTestCase.assertEmpty(errors.toString())
+ }
+
+ private fun loadKotlinInspections(): List<InspectionToolWrapper<InspectionProfileEntry, InspectionEP>> {
+ return InspectionToolRegistrar.getInstance().createTools().filter {
+ it.extension.pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID
+ }
+ }
+
+ private fun loadKotlinInspectionExtensions() =
+ LocalInspectionEP.LOCAL_INSPECTION.extensions.filter {
+ it.pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID
+ }
+
+ private fun desc(tool: InspectionToolWrapper<InspectionProfileEntry, InspectionEP>): String {
+ return tool.toString() + " ('" + tool.descriptionContextClass + "') " +
+ "in " + if (tool.extension == null) null else tool.extension.pluginDescriptor
+ }
+
+ fun testExtensionPoints() {
+ val shortNames = THashMap<String, LocalInspectionEP>()
+
+ @Suppress("DEPRECATION")
+ val inspectionEPs = Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)
+
+ val tools = inspectionEPs.size
+ val errors = StringBuilder()
+ for (ep in inspectionEPs) {
+ val shortName = ep.getShortName()
+ val ep1 = shortNames[shortName]
+ if (ep1 != null) {
+ errors.append(
+ "Short names must be unique: '" + shortName + "':\n" +
+ "inspection: '" + ep1.implementationClass + "' in '" + ep1.pluginDescriptor + "'\n" +
+ "; and '" + ep.implementationClass + "' in '" + ep.pluginDescriptor + "'"
+ )
+ }
+ shortNames.put(shortName, ep)
+ }
+ println("$tools inspection tools total via EP")
+
+ UsefulTestCase.assertEmpty(errors.toString())
+ }
+
+ fun testInspectionMappings() {
+ val toolWrappers = loadKotlinInspections()
+ val errors = StringBuilder()
+ toolWrappers.filter({ toolWrapper -> toolWrapper.extension == null }).forEach { toolWrapper ->
+ errors.append("Please add XML mapping for ").append(toolWrapper.tool::class.java)
+ }
+
+ UsefulTestCase.assertEmpty(errors.toString())
+ }
+
+ fun testMismatchedIds() {
+ val failMessages = mutableListOf<String>()
+ for (ep in loadKotlinInspectionExtensions()) {
+ val toolName = ep.implementationClass
+ val tool = ep.instantiateTool()
+ if (tool is LocalInspectionTool) {
+ checkValue(failMessages, toolName, "suppressId", ep.id, ep.getShortName(), tool.id)
+ checkValue(failMessages, toolName, "alternateId", ep.alternativeId, null, tool.alternativeID)
+ checkValue(failMessages, toolName, "shortName", ep.getShortName(), null, tool.shortName)
+ checkValue(failMessages, toolName, "runForWholeFile", null, "false", tool.runForWholeFile().toString())
+ }
+ }
+
+ UsefulTestCase.assertEmpty(StringUtil.join(failMessages, "\n"), failMessages)
+ }
+
+ fun testNotEmptyToolNames() {
+ val failMessages = mutableListOf<String>()
+ for (ep in LocalInspectionEP.LOCAL_INSPECTION.extensions) {
+ val toolName = ep.implementationClass
+ if (ep.getDisplayName().isNullOrEmpty()) {
+ failMessages.add(toolName + ": toolName is not set, tool won't be available in `run inspection` action")
+ }
+ }
+ UsefulTestCase.assertEmpty(failMessages.joinToString("\n"), failMessages)
+ }
+
+ private fun checkValue(
+ failMessages: MutableCollection<String>,
+ toolName: String,
+ attributeName: String,
+ xmlValue: String?,
+ defaultXmlValue: String?,
+ javaValue: String?
+ ) {
+ if (StringUtil.isNotEmpty(xmlValue)) {
+ if (javaValue != xmlValue) {
+ failMessages.add("$toolName: mismatched $attributeName. Xml: $xmlValue; Java: $javaValue")
+ }
+ } else if (StringUtil.isNotEmpty(javaValue)) {
+ if (javaValue != defaultXmlValue) {
+ failMessages.add("$toolName: $attributeName overridden in wrong way, will work in tests only. Please set appropriate $attributeName value in XML ($javaValue)")
+ }
+ }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt
index 2d8d8c3..38b04d3 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt
@@ -7,6 +7,7 @@
import com.intellij.codeInsight.intention.IntentionActionBean
import com.intellij.codeInsight.intention.IntentionManager
+import com.intellij.codeInsight.intention.impl.config.IntentionManagerImpl
import com.intellij.openapi.extensions.Extensions
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.UsefulTestCase
@@ -56,7 +57,7 @@
private fun String.isXmlIntentionName() = startsWith("Add") && endsWith("ToManifest")
private fun loadKotlinIntentions(): List<IntentionActionBean> {
- val extensionPoint = Extensions.getRootArea().getExtensionPoint(IntentionManager.EP_INTENTION_ACTIONS)
+ val extensionPoint = Extensions.getRootArea().getExtensionPoint(IntentionManagerImpl.EP_INTENTION_ACTIONS)
return extensionPoint.extensions.toList().filter {
it.pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID
}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt.193
new file mode 100644
index 0000000..2d8d8c3
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionDescriptionTest.kt.193
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.intentions
+
+import com.intellij.codeInsight.intention.IntentionActionBean
+import com.intellij.codeInsight.intention.IntentionManager
+import com.intellij.openapi.extensions.Extensions
+import com.intellij.testFramework.LightPlatformTestCase
+import com.intellij.testFramework.UsefulTestCase
+import org.jetbrains.kotlin.idea.KotlinPluginUtil
+import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
+import org.junit.runner.RunWith
+import java.io.File
+
+@RunWith(JUnit3WithIdeaConfigurationRunner::class)
+class IntentionDescriptionTest : LightPlatformTestCase() {
+
+ private val necessaryNormalNames = listOf("description.html", "before.kt.template", "after.kt.template")
+ private val necessaryXmlNames = listOf("description.html", "before.xml.template", "after.xml.template")
+ private val necessaryMavenNames = listOf("description.html")
+
+ fun testDescriptionsAndShortNames() {
+ val intentionTools = loadKotlinIntentions()
+ val errors = StringBuilder()
+ for (tool in intentionTools) {
+ val className = tool.className
+ val shortName = className.substringAfterLast(".").replace("$", "")
+ val directory = File("idea/resources-en/intentionDescriptions/$shortName")
+ if (!directory.exists() || !directory.isDirectory) {
+ if (tool.categories != null) {
+ errors.append("No description directory for intention '").append(className).append("'\n")
+ }
+ } else {
+ val necessaryNames = when {
+ shortName.isMavenIntentionName() -> necessaryMavenNames
+ shortName.isXmlIntentionName() -> necessaryXmlNames
+ else -> necessaryNormalNames
+ }
+ for (fileName in necessaryNames) {
+ val file = directory.resolve(fileName)
+ if (!file.exists() || !file.isFile) {
+ errors.append("No description file $fileName for intention '").append(className).append("'\n")
+ }
+ }
+ }
+ }
+
+ UsefulTestCase.assertEmpty(errors.toString())
+ }
+
+ private fun String.isMavenIntentionName() = startsWith("MavenPlugin")
+
+ private fun String.isXmlIntentionName() = startsWith("Add") && endsWith("ToManifest")
+
+ private fun loadKotlinIntentions(): List<IntentionActionBean> {
+ val extensionPoint = Extensions.getRootArea().getExtensionPoint(IntentionManager.EP_INTENTION_ACTIONS)
+ return extensionPoint.extensions.toList().filter {
+ it.pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt
index ccde3ea..7c664f5 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.idea.navigation
import com.intellij.ide.util.gotoByName.FilteringGotoByModel
-import com.intellij.lang.Language
+import com.intellij.ide.util.gotoByName.LanguageRef
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.testFramework.UsefulTestCase
@@ -19,7 +19,7 @@
@JvmStatic
@JvmOverloads
fun checkGotoDirectives(
- model: FilteringGotoByModel<Language>,
+ model: FilteringGotoByModel<LanguageRef>,
editor: Editor,
nonProjectSymbols: Boolean = false,
checkNavigation: Boolean = false
diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt.193
new file mode 100644
index 0000000..ccde3ea
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoCheck.kt.193
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.navigation
+
+import com.intellij.ide.util.gotoByName.FilteringGotoByModel
+import com.intellij.lang.Language
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.testFramework.UsefulTestCase
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
+import org.jetbrains.kotlin.test.util.renderAsGotoImplementation
+import org.junit.Assert
+import kotlin.test.assertEquals
+
+object GotoCheck {
+ @JvmStatic
+ @JvmOverloads
+ fun checkGotoDirectives(
+ model: FilteringGotoByModel<Language>,
+ editor: Editor,
+ nonProjectSymbols: Boolean = false,
+ checkNavigation: Boolean = false
+ ) {
+ val documentText = editor.document.text
+ val searchTextList = InTextDirectivesUtils.findListWithPrefixes(documentText, "// SEARCH_TEXT:")
+ Assert.assertFalse(
+ "There's no search text in test data file given. Use '// SEARCH_TEXT:' directive",
+ searchTextList.isEmpty()
+ )
+
+ val expectedReferences =
+ InTextDirectivesUtils.findLinesWithPrefixesRemoved(documentText, "// REF:").map { input -> input.trim { it <= ' ' } }
+ val includeNonProjectSymbols = nonProjectSymbols || InTextDirectivesUtils.isDirectiveDefined(documentText, "// CHECK_BOX")
+
+ val searchText = searchTextList.first()
+
+ val foundSymbols = model.getNames(includeNonProjectSymbols).filter { it?.startsWith(searchText) ?: false }.flatMap {
+ model.getElementsByName(it, includeNonProjectSymbols, "$it*").toList()
+ }
+
+ val inexactMatching = InTextDirectivesUtils.isDirectiveDefined(documentText, "// ALLOW_MORE_RESULTS")
+ val renderedSymbols = foundSymbols.map { (it as PsiElement).renderAsGotoImplementation() }
+
+ if (checkNavigation && (expectedReferences.size != 1 || inexactMatching)) {
+ error("Cannot check navigation targets when multiple references are expected")
+ }
+
+ if (inexactMatching) {
+ UsefulTestCase.assertContainsElements(renderedSymbols, expectedReferences)
+ } else {
+ UsefulTestCase.assertOrderedEquals(renderedSymbols.sorted(), expectedReferences)
+ }
+ if (!checkNavigation) return
+
+ assertNavigationElementMatches(foundSymbols.single() as PsiElement, documentText)
+ }
+
+ @JvmStatic
+ fun assertNavigationElementMatches(resolved: PsiElement, textWithDirectives: String) {
+ val expectedBinaryFile = InTextDirectivesUtils.findStringWithPrefixes(textWithDirectives, "// BINARY:")
+ val expectedSourceFile = InTextDirectivesUtils.findStringWithPrefixes(textWithDirectives, "// SRC:")
+ assertEquals(expectedBinaryFile, getFileWithDir(resolved))
+ val srcElement = resolved.navigationElement
+ Assert.assertNotEquals(srcElement, resolved)
+ assertEquals(expectedSourceFile, getFileWithDir(srcElement))
+ }
+
+ // TODO: move somewhere
+ fun getFileWithDir(resolved: PsiElement): String {
+ val targetFile = resolved.containingFile
+ val targetDir = targetFile.parent
+ return targetDir!!.name + "/" + targetFile.name
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt b/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt
index 8c65f9b..9fd4aa9 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt
@@ -26,7 +26,7 @@
.invoke(model, (myFixture.editor as EditorEx).dataContext)
val actualItems = (0 until model.size()).map {
- NavBarPresentation.calcPresentableText(model[it])
+ NavBarPresentation.calcPresentableText(model[it], false)
}
val expectedItems = InTextDirectivesUtils.findListWithPrefixes(psiFile.text, "// NAV_BAR_ITEMS:")
assertOrderedEquals(actualItems, expectedItems)
diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt.193
new file mode 100644
index 0000000..8c65f9b
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/navigationToolbar/AbstractKotlinNavBarTest.kt.193
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.navigationToolbar
+
+import com.intellij.ide.navigationToolbar.NavBarModel
+import com.intellij.ide.navigationToolbar.NavBarModelExtension
+import com.intellij.ide.navigationToolbar.NavBarPresentation
+import com.intellij.openapi.actionSystem.DataContext
+import com.intellij.openapi.editor.ex.EditorEx
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
+
+
+abstract class AbstractKotlinNavBarTest : KotlinLightCodeInsightFixtureTestCase() {
+
+ // inspired by: com.intellij.ide.navigationToolbar.JavaNavBarTest#assertNavBarModel
+ protected fun doTest(testPath: String) {
+ val psiFile = myFixture.configureByFile(testDataFile().name)
+ val model = NavBarModel(myFixture.project)
+
+ model::class.java.getDeclaredMethod("updateModel", DataContext::class.java)
+ .apply { isAccessible = true }
+ .invoke(model, (myFixture.editor as EditorEx).dataContext)
+
+ val actualItems = (0 until model.size()).map {
+ NavBarPresentation.calcPresentableText(model[it])
+ }
+ val expectedItems = InTextDirectivesUtils.findListWithPrefixes(psiFile.text, "// NAV_BAR_ITEMS:")
+ assertOrderedEquals(actualItems, expectedItems)
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt
index 4b0b9bd..63c5a48 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt
@@ -12,5 +12,5 @@
// FIX ME WHEN BUNCH 193 REMOVED
fun invokeIntentionCompat(action: IntentionAction, file: PsiFile, editor: Editor) {
- CodeInsightTestFixtureImpl.invokeIntention(action, file, editor, action.text)
+ CodeInsightTestFixtureImpl.invokeIntention(action, file, editor)
}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt.193
new file mode 100644
index 0000000..4b0b9bd
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/compat.kt.193
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.quickfix
+
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiFile
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
+
+// FIX ME WHEN BUNCH 193 REMOVED
+fun invokeIntentionCompat(action: IntentionAction, file: PsiFile, editor: Editor) {
+ CodeInsightTestFixtureImpl.invokeIntention(action, file, editor, action.text)
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt
new file mode 100644
index 0000000..a7c5715
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt
@@ -0,0 +1,874 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import com.intellij.refactoring.suggested.BaseSignatureChangePresentationTest
+
+class KotlinSignatureChangePresentationTest : BaseSignatureChangePresentationTest() {
+ override val refactoringSupport = KotlinSuggestedRefactoringSupport()
+
+ private fun signature(
+ name: String,
+ type: String?,
+ parameters: List<Parameter>,
+ receiverType: String? = null
+ ): Signature? {
+ return Signature.create(
+ name,
+ type,
+ parameters,
+ KotlinSignatureAdditionalData(DeclarationType.FUN, receiverType)
+ )
+ }
+
+ fun testAddParameters() {
+ val oldSignature = signature(
+ "foo",
+ "String",
+ listOf(Parameter(0, "p1", "Int")),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ "String",
+ listOf(
+ Parameter(Any(), "p0", "Any"),
+ Parameter(0, "p1", "Int"),
+ Parameter(Any(), "p2", "Long")
+ ),
+ "Any"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any.'
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ ': String'
+ New:
+ 'fun '
+ 'Any.'
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (added):
+ 'p0'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ ': String'
+ """.trimIndent()
+ )
+ }
+
+ fun testSwapParameters() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveParameter() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReorderParameters() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(3, "p4", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(3, "p4", "Any"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group (id = 2, moved):
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 2, moved):
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeFunctionName() {
+ val oldSignature = signature("foo", null, emptyList())!!
+ val newSignature = signature("bar", null, emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo' (modified)
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'bar' (modified)
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReturnType() {
+ val oldSignature = signature("foo", "Any", emptyList())!!
+ val newSignature = signature("foo", "String", emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'Any' (modified)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'String' (modified)
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReturnType() {
+ val oldSignature = signature("foo", null, emptyList())!!
+ val newSignature = signature("foo", "String", emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': String' (added)
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveReturnType() {
+ val oldSignature = signature("foo", "Any", emptyList())!!
+ val newSignature = signature("foo", null, emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': Any' (removed)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeParameterName() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1New", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+""".trimIndent()
+ )
+ }
+
+ fun testChangeTwoParameterNames() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1New", "Int"),
+ Parameter(1, "p2New", "Long")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2' (modified)
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2New' (modified)
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveAndRenameParameter() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1New", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveParameterAndChangeFunctionName() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "fooNew",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo' (modified)
+ '('
+ LineBreak('', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'fooNew' (modified)
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiver() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList()
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Any.' (added)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveReceiver() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList()
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any.' (removed)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReceiverType() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "String"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'String' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeDefaultValues() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int", KotlinParameterAdditionalData("1", "")),
+ Parameter(1, "p2", "Int", KotlinParameterAdditionalData("2", "")),
+ Parameter(2, "p3", "Int", KotlinParameterAdditionalData("3", "")),
+ Parameter(3, "p4", "Int")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int", KotlinParameterAdditionalData("1", "")),
+ Parameter(1, "p2", "Int", KotlinParameterAdditionalData("22", "")),
+ Parameter(2, "p3", "Int"),
+ Parameter(3, "p4", "Int", KotlinParameterAdditionalData("4", ""))
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ' = '
+ '1'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '2' (modified)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Int'
+ ' = ' (removed)
+ '3' (removed)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ' = '
+ '1'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '22' (modified)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Int'
+ ' = ' (added)
+ '4' (added)
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt
new file mode 100644
index 0000000..70d7985
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt
@@ -0,0 +1,585 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.fileTypes.LanguageFileType
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringAvailabilityTest
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.resolve.ImportPath
+
+class KotlinSuggestedRefactoringAvailabilityTest : BaseSuggestedRefactoringAvailabilityTest() {
+ override val fileType: LanguageFileType
+ get() = KotlinFileType.INSTANCE
+
+ override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ fun testNotAvailableWithSyntaxError() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(", p2: Any")
+ },
+ {
+ myFixture.type(", p")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testInsertTrailingComma() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(",")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testChangeNonVirtualPropertyType() {
+ doTest(
+ "val v: <caret>String = \"\"",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeParameterTypeNonVirtual() {
+ doTest(
+ "fun foo(p: <caret>String) {}",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeReturnTypeNonVirtual() {
+ doTest(
+ "fun foo(): <caret>String = \"\"",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeLocalVariableType() {
+ doTest(
+ """
+ fun foo() {
+ val local: <caret>Int
+ local = 10
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Long")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testAddLocalVariableType() {
+ doTest(
+ """
+ fun foo() {
+ var local<caret> = 10
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Long")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testTypeLocalVariableBeforeExpression() {
+ doTest(
+ """
+ """.trimIndent(),
+ {
+ myFixture.type("val ")
+ },
+ {
+ myFixture.type("cod")
+ },
+ {
+ myFixture.type("e = ")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testChangeParameterTypeAndName() {
+ doTest(
+ """
+ interface I {
+ fun foo(p: <caret>Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "String")
+ editor.caretModel.moveToOffset(editor.caretModel.offset - "p: ".length)
+ replaceTextAtCaret("p", "pNew")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages"))
+ )
+ }
+
+ fun testRenameTwoParameters() {
+ doTest(
+ """
+ interface I {
+ fun foo(<caret>p1: Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("p1", "p1New")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + "p1New: Int, ".length)
+ replaceTextAtCaret("p2", "p2New")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages"))
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTest(
+ """
+ class C {
+ open fun foo(p1: <caret>Int, p2: Int) {
+ }
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides"))
+ )
+ }
+
+ fun testChangeParameterTypeForAbstract() {
+ doTest(
+ """
+ abstract class C {
+ abstract fun foo(p1: <caret>Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations"))
+ )
+ }
+
+ fun testChangeParameterTypeInInterface() {
+ doTest(
+ """
+ interface I {
+ fun foo(p1: <caret>Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations"))
+ )
+ }
+
+ fun testChangeParameterTypeInInterfaceWithBody() {
+ doTest(
+ """
+ interface I {
+ fun foo(p1: <caret>Int, p2: Int) {}
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides"))
+ )
+ }
+
+ fun testChangeTypeOfPropertyWithImplementationInInterface() {
+ doTest(
+ """
+ interface I {
+ val p: <caret>Int
+ get() = 0
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("p", "overrides"))
+ )
+ }
+
+ fun testSpecifyExplicitType() {
+ doTest(
+ """
+ open class C {
+ open fun foo()<caret> = 1
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testRemoveExplicitType() {
+ doTest(
+ """
+ open class C {
+ open fun foo(): Int<caret> = 1
+ }
+ """.trimIndent(),
+ {
+ deleteTextBeforeCaret(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClass() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun foo(): <caret>C.Nested
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClassForReceiverType() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun <caret>C.Nested.foo()
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClassForParameterType() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun foo(p: <caret>C.Nested)
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportAnotherType() {
+ doTest(
+ """
+ import java.util.Date
+
+ interface I {
+ fun foo(): <caret>Date
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Date", "java.sql.Date")
+ },
+ {
+ removeImport("java.util.Date")
+ addImport("java.sql.Date")
+ },
+ {
+ replaceTextAtCaret("java.sql.Date", "Date")
+ },
+ expectedAvailability = Availability.NotAvailable,
+ expectedAvailabilityAfterResolve = Availability.Available((changeSignatureAvailableTooltip("foo", "implementations")))
+ )
+ }
+
+ fun testDuplicateProperty() {
+ doTest(
+ """
+ const val <caret>CONST1 = 1
+ """.trimIndent(),
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DUPLICATE)
+ },
+ {
+ replaceTextAtCaret("CONST1", "CONST2")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testDuplicateMethod() {
+ doTest(
+ """
+ class Test {
+ fun <caret>foo(p: Int) {}
+ }
+ """.trimIndent(),
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DUPLICATE)
+ },
+ {
+ replaceTextAtCaret("foo", "bar")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testNotDuplicateMethod() {
+ doTest(
+ """
+ class Test {
+ fun <caret>foo(p: Int) {}
+ fun foo(p: String) {}
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("foo", "bar")
+ },
+ expectedAvailability = Availability.Available(renameAvailableTooltip("foo", "bar"))
+ )
+ }
+
+
+ fun testUnusedLocal() {
+ doTest(
+ """
+ fun foo() {
+ val local<caret> = 0
+ }
+ """.trimIndent(),
+ {
+ myFixture.type("123")
+ },
+ expectedAvailability = Availability.Available(renameAvailableTooltip("local", "local123")),
+ expectedAvailabilityAfterBackgroundAmend = Availability.Disabled
+ )
+ }
+
+ fun testPrivateMethod() {
+ doTest(
+ """
+ private fun foo(<caret>) {
+ }
+ """.trimIndent(),
+ {
+ myFixture.type("p: Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages")),
+ expectedAvailabilityAfterBackgroundAmend = Availability.Disabled
+ )
+ }
+
+ fun testAddOptionalParameter() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(", p2: Int = 2")
+ },
+ expectedAvailability = Availability.Disabled,
+ )
+ }
+
+ fun testAddOptionalParameterWithOverrides() {
+ doTest(
+ """
+ interface I {
+ fun foo(p1: Int<caret>)
+ }
+
+ class C : I {
+ override fun foo(p1: Int) {
+ }
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(", p2: Int = 2")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ )
+ }
+
+ fun testAddOptionalParameterNotLast() {
+ doTest(
+ """
+ fun foo(<caret>p1: Int) {
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type("p0: Int = 0, ")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages")),
+ )
+ }
+
+ fun testAddOptionalParameterAndRenameParameter() {
+ doTest(
+ """
+ fun foo(<caret>p1: Int) {
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("p1", "p1New")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + "p1New: Int".length)
+ myFixture.type(", p2: Int = 2")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages")),
+ )
+ }
+
+ fun testAddTwoParameters() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(", p2: Int, p3: Int = 3")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages")),
+ )
+ }
+
+ fun testExpectedFunction() {
+ ignoreErrors = true
+ doTest(
+ """
+ expect fun foo()<caret>
+ """.trimIndent(),
+ {
+ myFixture.type(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "actual declarations")),
+ )
+ }
+
+ fun testMemberInsideExpectedClass() {
+ ignoreErrors = true
+ doTest(
+ """
+ expect class C {
+ fun foo()<caret>
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "actual declarations")),
+ )
+ }
+
+ fun testMemberDeepInsideExpectedClass() {
+ ignoreErrors = true
+ doTest(
+ """
+ expect class C {
+ class Nested {
+ fun foo()<caret>
+ }
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "actual declarations")),
+ )
+ }
+
+ private fun addImport(fqName: String) {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+
+ private fun removeImport(fqName: String) {
+ (file as KtFile).importList!!.imports.first { it.importedFqName?.asString() == fqName }.delete()
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt
new file mode 100644
index 0000000..5075217
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.lang.Language
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.FileType
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiFile
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringChangeCollectorTest
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.test.runTest
+
+class KotlinSuggestedRefactoringChangeCollectorTest : BaseSuggestedRefactoringChangeCollectorTest<KtNamedFunction>() {
+ override val fileType: FileType
+ get() = KotlinFileType.INSTANCE
+
+ override val language: Language
+ get() = KotlinLanguage.INSTANCE
+
+ override fun addDeclaration(file: PsiFile, text: String): KtNamedFunction {
+ val psiFactory = KtPsiFactory(project)
+ return (file as KtFile).add(psiFactory.createDeclaration(text)) as KtNamedFunction
+ }
+
+ override fun Signature.presentation(labelForParameterId: (Any) -> String?): String {
+ return buildString {
+ append("fun ")
+ val receiverType = (additionalData as KotlinSignatureAdditionalData?)?.receiverType
+ if (receiverType != null) {
+ append(receiverType)
+ append(".")
+ }
+ append(name)
+ append("(")
+ parameters.joinTo(this, separator = ", ") { it.presentation(labelForParameterId(it.id)) }
+ append(")")
+ if (type != null) {
+ append(": ")
+ append(type)
+ }
+ }
+ }
+
+ private fun Parameter.presentation(label: String?): String {
+ return buildString {
+ if (modifiers.isNotEmpty()) {
+ append(modifiers)
+ append(" ")
+ }
+ append(name)
+ append(": ")
+ append(type)
+ if (label != null) {
+ append(" (")
+ append(label)
+ append(")")
+ }
+ }
+ }
+
+ private fun createType(text: String): KtTypeReference {
+ return KtPsiFactory(project).createType(text)
+ }
+
+ private fun createParameter(text: String): KtParameter {
+ return KtPsiFactory(project).createParameter(text)
+ }
+
+ fun testAddParameter() {
+ doTest(
+ "fun foo(p1: Int) {}",
+ { it.valueParameterList!!.addParameter(createParameter("p2: Int")) },
+ expectedOldSignature = "fun foo(p1: Int)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p2: Int (new))"
+ )
+ }
+
+ fun testRemoveParameter() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameterList!!.removeParameter(0) },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(p2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[1].typeReference = createType("Any?") },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p2: Any? (initialIndex = 1))"
+ )
+ }
+
+ fun testChangeParameterNames() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[0].setName("newP1") },
+ { it.valueParameters[1].setName("newP2") },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(newP1: Int (initialIndex = 0), newP2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testReplaceParameter() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[0].replace(createParameter("newP1: Long")) },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(newP1: Long (new), p2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersChangeTypesAndNames() {
+ doTest(
+ "fun foo(p1: Int, p2: Int, p3: Int) {}",
+ {
+ editor.caretModel.moveToOffset(it.valueParameters[2].textOffset)
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[0].typeReference = createType("Any?")
+ it.valueParameters[1].typeReference = createType("Long")
+ it.valueParameters[2].typeReference = createType("Double")
+ }
+ }
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[1].setName("newName")
+ }
+ }
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: Int, p3: Int)",
+ expectedNewSignature = "fun foo(p3: Any? (initialIndex = 2), newName: Long (initialIndex = 0), p2: Double (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersByCutPaste() {
+ doTest(
+ "fun foo(p1: Int, p2: String, p3: Char)",
+ {
+ val offset = it.valueParameters[1].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ editor.selectionModel.setSelection(offset, offset + ", p3: Char".length)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ val offset = it.valueParameters[0].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: String, p3: Char)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p3: Char (initialIndex = 2), p2: String (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersByCutPasteAfterChangingName() {
+ doTest(
+ "fun foo(p1: Int, p2: String, p3: Char)",
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[2].setName("p3New")
+ PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
+ }
+ }
+ },
+ {
+ val offset = it.valueParameters[1].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ editor.selectionModel.setSelection(offset, offset + ", p3New: Char".length)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ val offset = it.valueParameters[0].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: String, p3: Char)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p3New: Char (initialIndex = 2), p2: String (initialIndex = 1))"
+ )
+ }
+
+ override fun runTest() {
+ runTest { super.runTest() }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt
new file mode 100644
index 0000000..b6d6da9
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.FileType
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringChangeListenerTest
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.endOffset
+import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.ImportPath
+import org.jetbrains.kotlin.test.runTest
+
+class KotlinSuggestedRefactoringChangeListenerTest : BaseSuggestedRefactoringChangeListenerTest() {
+ override val fileType: FileType
+ get() = KotlinFileType.INSTANCE
+
+ fun test1() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p") }
+
+ perform("nextSignature: 'foo(p)'") { commitAll() }
+ perform { myFixture.type(":") }
+ perform { myFixture.type(" S") }
+ perform { myFixture.type("tr") }
+ perform("nextSignature: 'foo(p: Str)'") { commitAll() }
+ perform { myFixture.type("ing") }
+ perform("nextSignature: 'foo(p: String)'") { commitAll() }
+
+ perform {
+ perform { myFixture.type(", ") }
+ commitAll()
+ }
+ }
+
+ fun testCompletion() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: DoubleArra") }
+ perform("nextSignature: 'foo(p: DoubleArra)'", "nextSignature: 'foo(p: DoubleArray)'") { myFixture.completeBasic() }
+ }
+
+ fun testChangeOutsideSignature() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("reset") {
+ insertString(editor.document.textLength, "\nval")
+ }
+ }
+
+ fun testEditOtherSignature() {
+ setup("fun foo(<caret>) {}\nfun bar() = 0")
+
+ val otherFunction = (file as KtFile).declarations[1] as KtNamedFunction
+ val offset = otherFunction.valueParameterList!!.startOffset + 1
+ val marker = editor.document.createRangeMarker(offset, offset)
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("nextSignature: 'foo(p: A)'") { commitAll() }
+
+ perform("reset", "editingStarted: 'bar()'", "nextSignature: 'bar(p1: String)'") {
+ assert(marker.isValid)
+ insertString(marker.startOffset, "p1: String")
+ commitAll()
+ }
+ }
+
+ fun testChangeInAnotherFile() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("reset") {
+ setup("")
+ myFixture.type(" ")
+ }
+ }
+
+ fun testAddImport() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: Any)'") {
+ myFixture.type("p: Any")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: Any)'", "nextSignature: 'foo(p: Any)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: Any, p2: String)'") {
+ myFixture.type(", p2: String")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: Any, p2: String)'", "nextSignature: 'foo(p: Any, p2: String)'") {
+ addImport("java.util.Date")
+ }
+ }
+
+ fun testAddImportWithBlankLineInsertion() {
+ setup(
+ """
+ import foo.bar
+ fun foo(<caret>) {}
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: ArrayList)'") {
+ myFixture.type("p: ArrayList")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList)'", "nextSignature: 'foo(p: ArrayList)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>)'") {
+ myFixture.type("<String>")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>, p2: Any)'") {
+ myFixture.type(", p2: Any")
+ commitAll()
+ }
+ }
+
+ fun testAddImportWithBlankLinesRemoval() {
+ setup(
+ """
+ import foo.bar
+
+
+
+ fun foo(<caret>) {}
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: ArrayList)'") {
+ myFixture.type("p: ArrayList")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList)'", "nextSignature: 'foo(p: ArrayList)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>)'") {
+ myFixture.type("<String>")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>, p2: Any)'") {
+ myFixture.type(", p2: Any")
+ commitAll()
+ }
+ }
+
+ fun testReorderParameters() {
+ setup("fun foo(p1: String, p2: Any, p3<caret>: Int) {}")
+
+ perform("editingStarted: 'foo(p1: String, p2: Any, p3: Int)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ }
+ perform("nextSignature: 'foo(p1: String, p3: Int, p2: Any)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ }
+ perform("nextSignature: 'foo(p3: Int, p1: String, p2: Any)'") {
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p1: String, p3: Int, p2: Any)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_RIGHT)
+ commitAll()
+ }
+ }
+
+ fun testAddParameterViaPsi() {
+ setup("fun foo(p1: Int) {}")
+
+ val function = (file as KtFile).declarations.single() as KtFunction
+ perform(
+ "editingStarted: 'foo(p1: Int)'",
+ "nextSignature: 'foo(p1: Int,)'",
+ "nextSignature: 'foo(p1: Int,p2: Int)'",
+ "nextSignature: 'foo(p1: Int, p2: Int)'"
+ ) {
+ executeCommand {
+ runWriteAction {
+ function.valueParameterList!!.addParameter(KtPsiFactory(project).createParameter("p2: Int"))
+ }
+ }
+ }
+ }
+
+ fun testCommentTyping() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p1: Any)'") {
+ myFixture.type("p1: Any")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type("/*")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type(" this is comment for parameter")
+ commitAll()
+ }
+
+ perform("nextSignature: 'foo(p1: Any/* this is comment for parameter*/)'") {
+ myFixture.type("*/")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type(", p2: Int /*")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type("this is comment for another parameter")
+ commitAll()
+ }
+
+ perform("nextSignature: 'foo(p1: Any/* this is comment for parameter*/, p2: Int /*this is comment for another parameter*/)'") {
+ myFixture.type("*/")
+ commitAll()
+ }
+ }
+
+ fun testAddReturnType() {
+ setup(
+ """
+ interface I {
+ fun foo()<caret>
+ }
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'") { myFixture.type(": String") }
+
+ perform("nextSignature: 'foo(): String'") { commitAll() }
+ }
+
+ fun testNewLocal() {
+ setup(
+ """
+ fun foo() {
+ <caret>
+ print(a)
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a")
+ commitAll()
+ myFixture.type("bcd")
+ commitAll()
+ }
+ }
+
+ fun testNewFunction() {
+ setup(
+ """
+ interface I {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("fun foo_bar123(_p1: Int)")
+ commitAll()
+ }
+ }
+
+ fun testNewProperty() {
+ setup(
+ """
+ interface I {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val prop: I")
+ commitAll()
+
+ myFixture.type("nt")
+ commitAll()
+ }
+ }
+
+ fun testNewLocalWithNewUsage() {
+ setup(
+ """
+ fun foo() {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a = 10")
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ENTER)
+ myFixture.type("print(a)")
+ commitAll()
+ }
+
+ perform("editingStarted: 'a'", "nextSignature: 'abcd'") {
+ val variable = file.findDescendantOfType<KtProperty>()!!
+ myFixture.editor.caretModel.moveToOffset(variable.nameIdentifier!!.endOffset)
+ myFixture.type("bcd")
+ commitAll()
+ }
+ }
+
+ fun testNewLocalBeforeExpression() {
+ setup(
+ """
+ fun foo(p: Int) {
+ <caret>p * p
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a")
+ commitAll()
+ }
+ perform {
+ myFixture.type("bcd = ")
+ commitAll()
+ }
+ }
+
+ fun testNewClassWithConstructor() {
+ setup("")
+
+ perform {
+ myFixture.type("class C")
+ commitAll()
+ }
+ perform {
+ myFixture.type("(p: Int)")
+ commitAll()
+ }
+ }
+
+ fun testNewSecondaryConstructor() {
+ setup(
+ """
+ class C {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("constructor(p1: Int)")
+ commitAll()
+ }
+ perform {
+ myFixture.type("(, p2: String)")
+ commitAll()
+ }
+ }
+
+ fun testRenameComponentVar() {
+ setup(
+ """
+ fun f() {
+ val (<caret>a, b) = f()
+ }
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'a'", "nextSignature: 'newa'") {
+ myFixture.type("new")
+ commitAll()
+ }
+ }
+
+ override fun runTest() {
+ runTest { super.runTest() }
+ }
+
+ private fun addImport(fqName: String) {
+ executeCommand {
+ runWriteAction {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+ }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt
new file mode 100644
index 0000000..8aaa1da
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt
@@ -0,0 +1,1588 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.LanguageFileType
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringTest
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution
+import com.intellij.refactoring.suggested.SuggestedRefactoringProviderImpl
+import com.intellij.refactoring.suggested._suggestedChangeSignatureNewParameterValuesForTests
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.resolve.ImportPath
+import org.jetbrains.kotlin.test.runTest
+
+class KotlinSuggestedRefactoringTest : BaseSuggestedRefactoringTest() {
+ override val fileType: LanguageFileType
+ get() = KotlinFileType.INSTANCE
+
+ override fun setUp() {
+ super.setUp()
+ _suggestedChangeSignatureNewParameterValuesForTests = {
+ SuggestedRefactoringExecution.NewParameterValue.Expression(KtPsiFactory(project).createExpression("default$it"))
+ }
+ }
+
+ override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ fun testAddParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p1: Int, p2: Any<caret>) {
+ foo(1, default0)
+ }
+
+ fun bar() {
+ foo(2, default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", p2: Any") }
+ )
+ }
+
+ fun testRemoveParameter() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, p2: Int<caret>) {
+ foo(null, 1)
+ }
+
+ fun bar() {
+ foo(1, 2)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p1: Any?<caret>) {
+ foo(null)
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ deleteTextBeforeCaret(", p2: Int")
+ }
+ )
+ }
+
+ fun testReorderParameters1() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, p2: Int, p3: Boolean<caret>) {
+ foo(null, 1, true)
+ }
+
+ fun bar() {
+ foo(1, 2, false)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p3: Boolean, p1: Any?, p2: Int) {
+ foo(true, null, 1)
+ }
+
+ fun bar() {
+ foo(false, 1, 2)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT) },
+ { myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT) },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testReorderParameters2() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, <caret>p2: Int, p3: Boolean) {
+ foo(null, 1, true)
+ }
+
+ fun bar() {
+ foo(1, 2, false)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p2: Int, p1: Any?, p3: Boolean) {
+ foo(1, null, true)
+ }
+
+ fun bar() {
+ foo(2, 1, false)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset - 10)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ {
+ myFixture.type(", ")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + 10)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE)
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: <caret>Any)
+ }
+
+ class C : I {
+ override fun foo(p: Any) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeExpectFunction() {
+ ignoreErrorsBefore = true
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ "expect fun foo(p: <caret>String)",
+ "expect fun foo(p: <caret>Any)",
+ "actual declarations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testUnresolvedParameterType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: XXX)
+ }
+
+ class C : I {
+ override fun foo(p: XXX) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "XXX")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeWithImportInsertion() {
+ myFixture.addFileToProject(
+ "X.kt",
+ """
+ package xxx
+ class X
+ """.trimIndent()
+ )
+
+ val otherFile = myFixture.addFileToProject(
+ "Other.kt",
+ """
+ class D : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent()
+ )
+
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ import xxx.X
+
+ interface I {
+ fun foo(p: <caret>X)
+ }
+
+ class C : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "X")
+ },
+ {
+ addImport("xxx.X")
+ }
+ )
+
+ assertEquals(
+ """
+ import xxx.X
+
+ class D : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent(),
+ otherFile.text
+ )
+ }
+
+ fun testChangeReturnType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(): <caret>String
+ }
+
+ class C : I {
+ override fun foo(): String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(): <caret>Any
+ }
+
+ class C : I {
+ override fun foo(): Any = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testAddReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo()<caret>
+ }
+
+ class C : I {
+ override fun foo() {}
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(): String<caret>
+ }
+
+ class C : I {
+ override fun foo(): String {}
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ myFixture.type(": String")
+ }
+ )
+ }
+
+ fun testRemoveReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo()<caret>: String
+ }
+
+ class C : I {
+ override fun foo(): String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo()<caret>
+ }
+
+ class C : I {
+ override fun foo() = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ deleteTextAtCaret(": String")
+ }
+ )
+ }
+
+ fun testRenameAndAddReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo<caret>()
+ }
+
+ class C : I {
+ override fun foo() {}
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo<caret>New(): String
+ }
+
+ class C : I {
+ override fun fooNew(): String {}
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ val offset = editor.caretModel.offset
+ editor.document.insertString(offset, "New")
+ },
+ {
+ val offset = editor.caretModel.offset
+ editor.document.insertString(offset + "New()".length, ": String")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeWithImportReplaced() {
+ myFixture.addFileToProject(
+ "XY.kt",
+ """
+ package xxx
+ class X
+ class Y
+ """.trimIndent()
+ )
+
+ val otherFile = myFixture.addFileToProject(
+ "Other.kt",
+ """
+ import xxx.X
+
+ class D : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent()
+ )
+
+ doTestChangeSignature(
+ """
+ import xxx.X
+
+ interface I {
+ fun foo(p: <caret>X)
+ }
+ """.trimIndent(),
+ """
+ import xxx.Y
+
+ interface I {
+ fun foo(p: <caret>Y)
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ val offset = editor.caretModel.offset
+ editor.document.replaceString(offset, offset + "X".length, "Y")
+ },
+ {
+ addImport("xxx.Y")
+ removeImport("xxx.X")
+ }
+ )
+
+ assertEquals(
+ """
+ import xxx.Y
+
+ class D : I {
+ override fun foo(p: Y) {
+ }
+ }
+ """.trimIndent(),
+ otherFile.text
+ )
+ }
+
+ fun testPreserveCommentsAndFormatting() {
+ doTestChangeSignature(
+ """
+ class A : I {
+ override fun foo() {
+ }
+ }
+
+ interface I {
+ fun foo(<caret>)
+ }
+ """.trimIndent(),
+ """
+ class A : I {
+ override fun foo(p1: Int, p2: Long, p3: Any?) {
+ }
+ }
+
+ interface I {
+ fun foo(p1: Int/*comment 1*/, p2: Long/*comment 2*/,
+ p3: Any?/*comment 3*/<caret>)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.type("p1: Int/*comment 1*/")
+ },
+ {
+ myFixture.type(", p2: Long/*comment 2*/")
+ },
+ {
+ myFixture.type(",")
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ENTER)
+ myFixture.type("p3: Any?/*comment 3*/")
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testParameterCompletion() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ "package ppp\nclass Abcdef\nfun foo(<caret>p: Int) { }\nfun bar() { foo(1) }",
+ "package ppp\nclass Abcdef\nfun foo(abcdef: Abcdef, <caret>p: Int) { }\nfun bar() { foo(default0, 1) }",
+ "usages",
+ {
+ executeCommand {
+ runWriteAction {
+ myFixture.type("abcde")
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+ }
+ }
+ },
+ {
+ myFixture.completeBasic()
+ },
+ {
+ myFixture.finishLookup('\n')
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ myFixture.type(", ")
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+ }
+ }
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testRenameTwoParameters() {
+ doTestChangeSignature(
+ """
+ fun foo(<caret>p1: Int, p2: String) {
+ p1.hashCode()
+ p2.hashCode()
+ }
+ """.trimIndent(),
+ """
+ fun foo(<caret>p1New: Int, p2New: String) {
+ p1New.hashCode()
+ p2New.hashCode()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ val function = (file as KtFile).declarations.single() as KtFunction
+ function.valueParameters[0].setName("p1New")
+ function.valueParameters[1].setName("p2New")
+ }
+ )
+ }
+
+ fun testChangePropertyType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ var v: <caret>String
+ }
+
+ class C : I {
+ override var v: String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ var v: <caret>Any
+ }
+
+ class C : I {
+ override var v: Any = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedPresentation = """
+ Old:
+ 'var '
+ 'v'
+ ': '
+ 'String' (modified)
+ New:
+ 'var '
+ 'v'
+ ': '
+ 'Any' (modified)
+ """.trimIndent()
+ )
+ }
+
+ fun testRenameClass() {
+ doTestRename(
+ """
+ var v: C? = null
+
+ interface C<caret>
+ """.trimIndent(),
+ """
+ var v: CNew? = null
+
+ interface CNew<caret>
+ """.trimIndent(),
+ "C",
+ "CNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameLocalVar() {
+ doTestRename(
+ """
+ fun foo() {
+ var v<caret> = 0
+ v++
+ }
+ """.trimIndent(),
+ """
+ fun foo() {
+ var vNew<caret> = 0
+ vNew++
+ }
+ """.trimIndent(),
+ "v",
+ "vNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameComponentVar() {
+ doTestRename(
+ """
+ data class Pair<T1, T2>(val t1: T1, val t2: T2)
+
+ fun f(): Pair<String, Int> = Pair("a", 1)
+
+ fun g() {
+ val (a, b<caret>) = f()
+ b.hashCode()
+ }
+ """.trimIndent(),
+ """
+ data class Pair<T1, T2>(val t1: T1, val t2: T2)
+
+ fun f(): Pair<String, Int> = Pair("a", 1)
+
+ fun g() {
+ val (a, b1<caret>) = f()
+ b1.hashCode()
+ }
+ """.trimIndent(),
+ "b",
+ "b1",
+ {
+ myFixture.type("1")
+ }
+ )
+ }
+
+ fun testRenameLoopVar() {
+ doTestRename(
+ """
+ fun f(list: List<String>) {
+ for (s<caret> in list) {
+ s.hashCode()
+ }
+ }
+ """.trimIndent(),
+ """
+ fun f(list: List<String>) {
+ for (s1<caret> in list) {
+ s1.hashCode()
+ }
+ }
+ """.trimIndent(),
+ "s",
+ "s1",
+ {
+ myFixture.type("1")
+ }
+ )
+ }
+
+ fun testRenameParameter() {
+ doTestRename(
+ """
+ fun foo(p<caret>: String) {
+ p.hashCode()
+ }
+ """.trimIndent(),
+ """
+ fun foo(pNew<caret>: String) {
+ pNew.hashCode()
+ }
+ """.trimIndent(),
+ "p",
+ "pNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameParametersInOverrides() {
+ doTestRename(
+ """
+ interface I {
+ fun foo(p<caret>: String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ p.hashCode()
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(pNew<caret>: String)
+ }
+
+ class C : I {
+ override fun foo(pNew: String) {
+ pNew.hashCode()
+ }
+ }
+ """.trimIndent(),
+ "p",
+ "pNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testAddPrimaryConstructorParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ class C(private val x: String, y: Int<caret>)
+
+ fun foo() {
+ val c = C("a", 1)
+ }
+ """.trimIndent(),
+ """
+ class C(private val x: String, y: Int, z: Any<caret>)
+
+ fun foo() {
+ val c = C("a", 1, default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", z: Any") },
+ expectedPresentation = """
+ Old:
+ 'C'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'y'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'C'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'y'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'z'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddSecondaryConstructorParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ class C {
+ constructor(x: String<caret>)
+ }
+
+ fun foo() {
+ val c = C("a")
+ }
+ """.trimIndent(),
+ """
+ class C {
+ constructor(x: String, y: Int<caret>)
+ }
+
+ fun foo() {
+ val c = C("a", default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", y: Int") },
+ expectedPresentation = """
+ Old:
+ 'constructor'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ LineBreak('', false)
+ ')'
+ New:
+ 'constructor'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'y'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiver() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun <caret>foo()
+ }
+
+ class C : I {
+ override fun foo() {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun Int.<caret>foo()
+ }
+
+ class C : I {
+ override fun Int.foo() {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("Int.") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Int.' (added)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiverAndParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ fun <caret>foo() {
+ }
+
+ fun bar() {
+ foo()
+ }
+ """.trimIndent(),
+ """
+ fun Int.foo(o: Any<caret>) {
+ }
+
+ fun bar() {
+ default0.foo(default1)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("Int.") },
+ { repeat("foo(".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT) } },
+ { myFixture.type("o: Any") }
+ )
+ }
+
+ fun testRemoveReceiver() {
+ doTestChangeSignature(
+ """
+ fun <caret>Int.foo() {
+ }
+
+ fun bar() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ """
+ fun <caret>foo() {
+ }
+
+ fun bar() {
+ foo()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ repeat(4) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ }
+ )
+ }
+
+ fun testChangeReceiverType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun <caret>Int.foo()
+ }
+
+ class C : I {
+ override fun Int.foo() {
+ }
+ }
+
+ fun I.f() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun Any<caret>.foo()
+ }
+
+ class C : I {
+ override fun Any.foo() {
+ }
+ }
+
+ fun I.f() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ repeat("Int".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ myFixture.type("Any")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'Int' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Any' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReceiverTypeAndRemoveParameter() {
+ doTestChangeSignature(
+ """
+ fun <caret>Int.foo(p: Any) {}
+
+ fun bar() {
+ 1.foo("a")
+ }
+ """.trimIndent(),
+ """
+ fun Any.foo() {}
+
+ fun bar() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ repeat("Int".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ myFixture.type("Any")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + ".foo(".length)
+ repeat("p: Any".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ }
+ )
+ }
+
+ fun testAddVarargParameter() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: Int<caret>)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: Int, vararg s: String<caret>)
+ }
+
+ class C : I {
+ override fun foo(p: Int, vararg s: String) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", vararg s: String") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'vararg'
+ ' '
+ 's'
+ ': '
+ 'String'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ //TODO
+/*
+ fun testAddVarargModifier() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(vararg <caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(vararg p: Int) {
+ }
+ }
+ """.trimIndent(),
+ { myFixture.type("vararg ") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'vararg' (added)
+ ' '
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveVarargModifier() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>vararg p: Int)
+ }
+
+ class C : I {
+ override fun foo(vararg p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(<caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ {
+ deleteStringAtCaret("vararg ")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'vararg' (removed)
+ ' '
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+*/
+
+ fun testSwapConstructorParameters() {
+ doTestChangeSignature(
+ """
+ class C(
+ p1: Int,
+ p2: String<caret>
+ )
+
+ fun foo() {
+ C(1, "")
+ }
+ """.trimIndent(),
+ """
+ class C(
+ p2: String,
+ p1: Int
+ )
+
+ fun foo() {
+ C("", 1)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_MOVE_STATEMENT_UP_ACTION)
+ }
+ )
+ }
+
+ fun testChangeParameterTypeOfVirtualExtensionMethod() {
+ doTestChangeSignature(
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: <caret>String)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: <caret>Any)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: Any) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testAddParameterToVirtualExtensionMethod() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: String<caret>)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: String, p1: Int<caret>)
+
+ fun bar() {
+ 1.foo("a", default0)
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String, p1: Int) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.type(", p1: Int")
+ }
+ )
+ }
+
+ fun testAddParameterWithFullyQualifiedType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>)
+ }
+
+ class C : I {
+ override fun foo() {
+ }
+ }
+ """.trimIndent(),
+ """
+ import java.io.InputStream
+
+ interface I {
+ fun foo(p: java.io.InputStream)
+ }
+
+ class C : I {
+ override fun foo(p: InputStream) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("p: java.io.InputStream") }
+ )
+ }
+
+ fun testAddOptionalParameter() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p1: Int<caret>)
+ }
+
+ class C : I {
+ override fun foo(p1: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(1)
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p1: Int, p2: Int = 10<caret>)
+ }
+
+ class C : I {
+ override fun foo(p1: Int, p2: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(1)
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ myFixture.type(", p2: Int = 10")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReorderOptionalParameter() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>p1: Int, p2: Int = 10)
+ }
+
+ class C : I {
+ override fun foo(p1: Int, p2: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(2)
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p2: Int = 10, <caret>p1: Int)
+ }
+
+ class C : I {
+ override fun foo(p2: Int, p1: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(p1 = 2)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_RIGHT)
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReplaceTypeWithItsAlias() {
+ doTestChangeSignature(
+ """
+ typealias StringToUnit = (String) -> Unit
+
+ interface I {
+ fun foo(): <caret>(String) -> Unit
+ }
+
+ class C : I {
+ override fun foo(): (String) -> Unit {
+ throw UnsupportedOperationException()
+ }
+ }
+ """.trimIndent(),
+ """
+ typealias StringToUnit = (String) -> Unit
+
+ interface I {
+ fun foo(): <caret>StringToUnit
+ }
+
+ class C : I {
+ override fun foo(): StringToUnit {
+ throw UnsupportedOperationException()
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("(String) -> Unit", "StringToUnit")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ '(String) -> Unit' (modified)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'StringToUnit' (modified)
+ """.trimIndent()
+ )
+ }
+
+ fun testNewParameterValueReferencesAnotherParameter() {
+ _suggestedChangeSignatureNewParameterValuesForTests = {
+ val declaration = SuggestedRefactoringProviderImpl.getInstance(project).state!!.declaration
+ val codeFragment = KtPsiFactory(project).createExpressionCodeFragment("p1 * p1", declaration)
+ SuggestedRefactoringExecution.NewParameterValue.Expression(codeFragment.getContentElement()!!)
+ }
+ doTestChangeSignature(
+ """
+ fun foo(p1: Int<caret>) {
+ }
+
+ fun bar() {
+ foo(1)
+ foo(2)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p1: Int, p2: Int<caret>) {
+ }
+
+ fun bar() {
+ foo(1, 1 * 1)
+ foo(2, 2 * 2)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", p2: Int") }
+ )
+ }
+
+ override fun runTest() {
+ runTest { super.runTest() }
+ }
+
+ private fun addImport(fqName: String) {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+
+ private fun removeImport(fqName: String) {
+ (file as KtFile).importList!!.imports.first { it.importedFqName?.asString() == fqName }.delete()
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt
index 94a1868..0d77f58 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt
@@ -30,7 +30,7 @@
super.setUp()
val pomModelImpl = PomModelImpl(project)
- val treeAspect = TreeAspect(pomModelImpl)
+ val treeAspect = TreeAspect.getInstance(project)
val mockProject = project as MockProject
createAndRegisterKotlinCodeBlockModificationListener(mockProject, pomModelImpl, treeAspect)
diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt.193
new file mode 100644
index 0000000..94a1868
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractAdditionalResolveDescriptorRendererTest.kt.193
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.resolve
+
+import com.intellij.mock.MockProject
+import com.intellij.pom.PomModel
+import com.intellij.pom.core.impl.PomModelImpl
+import com.intellij.pom.tree.TreeAspect
+import org.jetbrains.kotlin.container.ComponentProvider
+import org.jetbrains.kotlin.container.get
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
+import org.jetbrains.kotlin.idea.project.IdeaEnvironment
+import org.jetbrains.kotlin.idea.project.ResolveElementCache
+import org.jetbrains.kotlin.psi.KtAnonymousInitializer
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtPsiUtil
+import org.jetbrains.kotlin.renderer.AbstractDescriptorRendererTest
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.TargetEnvironment
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.picocontainer.MutablePicoContainer
+
+abstract class AbstractAdditionalResolveDescriptorRendererTest : AbstractDescriptorRendererTest() {
+ override fun setUp() {
+ super.setUp()
+
+ val pomModelImpl = PomModelImpl(project)
+ val treeAspect = TreeAspect(pomModelImpl)
+
+ val mockProject = project as MockProject
+ createAndRegisterKotlinCodeBlockModificationListener(mockProject, pomModelImpl, treeAspect)
+ }
+
+ override fun tearDown() {
+ unregisterKotlinCodeBlockModificationListener(project as MockProject)
+
+ super.tearDown()
+ }
+
+ override fun getDescriptor(declaration: KtDeclaration, container: ComponentProvider): DeclarationDescriptor {
+ if (declaration is KtAnonymousInitializer || KtPsiUtil.isLocal(declaration)) {
+ return container.get<ResolveElementCache>()
+ .resolveToElements(listOf(declaration), BodyResolveMode.FULL)
+ .get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)!!
+ }
+ return container.get<ResolveSession>().resolveToDescriptor(declaration)
+ }
+
+ override val targetEnvironment: TargetEnvironment
+ get() = IdeaEnvironment
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt
index 7b72859..0320762 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt
@@ -12,9 +12,8 @@
internal fun createAndRegisterKotlinCodeBlockModificationListener(project: MockProject, pomModel: PomModel, treeAspect: TreeAspect) {
project.registerService(PomModel::class.java, pomModel)
- project.picoContainer.registerComponentInstance(
- KotlinCodeBlockModificationListener(project, treeAspect)
- )
+ project.registerService(TreeAspect::class.java, treeAspect)
+ project.registerService(KotlinCodeBlockModificationListener::class.java, KotlinCodeBlockModificationListener(project))
}
internal fun unregisterKotlinCodeBlockModificationListener(project: MockProject) {
diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt.193
new file mode 100644
index 0000000..7b72859
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt.193
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.resolve
+
+import com.intellij.mock.MockProject
+import com.intellij.pom.PomModel
+import com.intellij.pom.tree.TreeAspect
+import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
+
+internal fun createAndRegisterKotlinCodeBlockModificationListener(project: MockProject, pomModel: PomModel, treeAspect: TreeAspect) {
+ project.registerService(PomModel::class.java, pomModel)
+ project.picoContainer.registerComponentInstance(
+ KotlinCodeBlockModificationListener(project, treeAspect)
+ )
+}
+
+internal fun unregisterKotlinCodeBlockModificationListener(project: MockProject) {
+ val picoContainer = project.picoContainer
+ picoContainer.unregisterComponent(KotlinCodeBlockModificationListener::class.java)
+ picoContainer.unregisterComponent(PomModel::class.java)
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt
index c579bd2..5ab9362 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt
@@ -9,6 +9,7 @@
import com.intellij.ide.projectView.TreeStructureProvider
import com.intellij.ide.util.treeView.AbstractTreeStructureBase
import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.search.PsiSearchScopeUtil
import com.intellij.slicer.DuplicateMap
import com.intellij.slicer.SliceAnalysisParams
import com.intellij.slicer.SliceNode
@@ -63,7 +64,7 @@
else -> {
val chunks = usage.text
- if (!projectScope.contains(usage.element)) {
+ if (!PsiSearchScopeUtil.isInScope(projectScope, usage.element!!)) {
append("LIB ")
} else {
append(chunks.first().render() + " ")
diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt.193
new file mode 100644
index 0000000..c579bd2
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestUtil.kt.193
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.slicer
+
+import com.intellij.analysis.AnalysisScope
+import com.intellij.ide.projectView.TreeStructureProvider
+import com.intellij.ide.util.treeView.AbstractTreeStructureBase
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.slicer.DuplicateMap
+import com.intellij.slicer.SliceAnalysisParams
+import com.intellij.slicer.SliceNode
+import com.intellij.slicer.SliceRootNode
+import com.intellij.usages.TextChunk
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.psiUtil.contains
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
+import java.awt.Font
+
+internal class TestSliceTreeStructure(private val rootNode: SliceNode) : AbstractTreeStructureBase(rootNode.project) {
+ override fun getProviders() = emptyList<TreeStructureProvider>()
+
+ override fun getRootElement() = rootNode
+
+ override fun commit() {
+ }
+
+ override fun hasSomethingToCommit() = false
+}
+
+internal fun buildTreeRepresentation(rootNode: SliceNode): String {
+ val project = rootNode.element!!.project!!
+ val projectScope = GlobalSearchScope.projectScope(project)
+
+ fun TextChunk.render(): String {
+ var text = text
+ if (attributes.fontType == Font.BOLD) {
+ text = "<bold>$text</bold>"
+ }
+ return text
+ }
+
+ fun SliceNode.isSliceLeafValueClassNode() = this is HackedSliceLeafValueClassNode
+
+ fun process(node: SliceNode, indent: Int): String {
+ val usage = node.element!!.value
+
+ node.calculateDupNode()
+ val isDuplicated = !node.isSliceLeafValueClassNode() && node.duplicate != null
+
+ return buildString {
+ when {
+ node is SliceRootNode && usage.element is KtFile -> {
+ node.sortedChildren.forEach { append(process(it, indent)) }
+ return@buildString
+ }
+
+ // SliceLeafValueClassNode is package-private
+ node.isSliceLeafValueClassNode() -> append("[${node.nodeText}]\n")
+
+ else -> {
+ val chunks = usage.text
+ if (!projectScope.contains(usage.element)) {
+ append("LIB ")
+ } else {
+ append(chunks.first().render() + " ")
+ }
+
+ repeat(indent) { append('\t') }
+
+ if (usage is KotlinSliceDereferenceUsage) {
+ append("DEREFERENCE: ")
+ }
+
+ if (usage is KotlinSliceUsage) {
+ usage.mode.inlineCallStack.forEach {
+ append("(INLINE CALL ${it.function?.name}) ")
+ }
+ usage.mode.behaviourStack.reversed().joinTo(this, separator = "") { it.testPresentationPrefix }
+ }
+
+ if (isDuplicated) {
+ append("DUPLICATE: ")
+ }
+
+ chunks.slice(1 until chunks.size).joinTo(this, separator = "") { it.render() }
+
+ KotlinSliceUsageCellRenderer.containerSuffix(usage)?.let {
+ append(" ($it)")
+ }
+
+ append("\n")
+ }
+ }
+
+ if (!isDuplicated) {
+ node.sortedChildren.forEach { append(process(it, indent + 1)) }
+ }
+ }.replace(Regex("</bold><bold>"), "")
+ }
+
+ return process(rootNode, 0)
+}
+
+private val SliceNode.sortedChildren: List<SliceNode>
+ get() = children.sortedBy { it.value.element?.startOffset ?: -1 }
+
+internal fun testSliceFromOffset(
+ file: KtFile,
+ offset: Int,
+ doTest: (sliceProvider: KotlinSliceProvider, rootNode: SliceRootNode) -> Unit
+) {
+ val fileText = file.text
+ val flowKind = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// FLOW: ")
+ val withDereferences = InTextDirectivesUtils.isDirectiveDefined(fileText, "// WITH_DEREFERENCES")
+ val analysisParams = SliceAnalysisParams().apply {
+ dataFlowToThis = when (flowKind) {
+ "IN" -> true
+ "OUT" -> false
+ else -> throw AssertionError("Invalid flow kind: $flowKind")
+ }
+ showInstanceDereferences = withDereferences
+ scope = AnalysisScope(file.project)
+ }
+
+ val elementAtCaret = file.findElementAt(offset)!!
+ val sliceProvider = KotlinSliceProvider()
+ val expression = sliceProvider.getExpressionAtCaret(elementAtCaret, analysisParams.dataFlowToThis)!!
+ val rootUsage = sliceProvider.createRootUsage(expression, analysisParams)
+ val rootNode = SliceRootNode(file.project, DuplicateMap(), rootUsage)
+ doTest(sliceProvider, rootNode)
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt
index 5948b82..aa06dd5 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt
@@ -40,10 +40,10 @@
val text = myEditor.document.text
if (shouldCheckLineMarkers) {
- data.checkLineMarkers(DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(file), project), text)
+ data.checkLineMarkers(myFile, DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(file), project), text)
}
if (shouldCheckResult) {
- data.checkResult(infos, text)
+ data.checkResult(myFile, infos, text)
}
return infos
}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt.193
new file mode 100644
index 0000000..5948b82
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiHighlightingTest.kt.193
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.stubs
+
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
+import com.intellij.codeInsight.daemon.impl.HighlightInfo
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.project.DumbService
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.impl.cache.CacheManager
+import com.intellij.psi.impl.source.tree.TreeElement
+import com.intellij.psi.impl.source.tree.TreeUtil
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.search.UsageSearchContext
+import com.intellij.testFramework.ExpectedHighlightingData
+
+abstract class AbstractMultiHighlightingTest : AbstractMultiModuleTest() {
+
+ protected open val shouldCheckLineMarkers = false
+
+ protected open val shouldCheckResult = true
+
+ override fun checkHighlighting(data: ExpectedHighlightingData): Collection<HighlightInfo> {
+ data.init()
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments()
+
+ //to load text
+ ApplicationManager.getApplication().runWriteAction { TreeUtil.clearCaches(myFile.node as TreeElement) }
+
+ //to initialize caches
+ if (!DumbService.isDumb(project)) {
+ CacheManager.SERVICE.getInstance(myProject)
+ .getFilesWithWord("XXX", UsageSearchContext.IN_COMMENTS, GlobalSearchScope.allScope(myProject), true)
+ }
+
+ val infos = doHighlighting()
+
+ val text = myEditor.document.text
+ if (shouldCheckLineMarkers) {
+ data.checkLineMarkers(DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(file), project), text)
+ }
+ if (shouldCheckResult) {
+ data.checkResult(infos, text)
+ }
+ return infos
+ }
+}
\ No newline at end of file
diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
index 44f9706..9a89774 100644
--- a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
+++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
@@ -27,7 +27,6 @@
import com.intellij.lang.jvm.facade.JvmElementProvider
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.extensions.ExtensionsArea
-import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.*
@@ -37,7 +36,6 @@
import com.intellij.psi.impl.JavaClassSupersImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.meta.MetaDataContributor
-import com.intellij.psi.stubs.BinaryFileStubBuilders
import com.intellij.psi.util.JavaClassSupers
import junit.framework.TestCase
import org.jetbrains.kotlin.utils.PathUtil
@@ -104,7 +102,6 @@
}
private fun registerExtensionPoints(area: ExtensionsArea) {
- CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint::class.java)
CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193 b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193
new file mode 100644
index 0000000..44f9706
--- /dev/null
+++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193
@@ -0,0 +1,137 @@
+/*
+ * 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.j2k
+
+import com.intellij.codeInsight.ContainerProvider
+import com.intellij.codeInsight.NullableNotNullManager
+import com.intellij.codeInsight.NullableNotNullManagerImpl
+import com.intellij.codeInsight.runner.JavaMainMethodProvider
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.core.JavaCoreApplicationEnvironment
+import com.intellij.core.JavaCoreProjectEnvironment
+import com.intellij.lang.MetaLanguage
+import com.intellij.lang.jvm.facade.JvmElementProvider
+import com.intellij.openapi.extensions.Extensions
+import com.intellij.openapi.extensions.ExtensionsArea
+import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.*
+import com.intellij.psi.augment.PsiAugmentProvider
+import com.intellij.psi.augment.TypeAnnotationModifier
+import com.intellij.psi.compiled.ClassFileDecompilers
+import com.intellij.psi.impl.JavaClassSupersImpl
+import com.intellij.psi.impl.PsiTreeChangePreprocessor
+import com.intellij.psi.meta.MetaDataContributor
+import com.intellij.psi.stubs.BinaryFileStubBuilders
+import com.intellij.psi.util.JavaClassSupers
+import junit.framework.TestCase
+import org.jetbrains.kotlin.utils.PathUtil
+import java.io.File
+import java.net.URLClassLoader
+
+abstract class AbstractJavaToKotlinConverterForWebDemoTest : TestCase() {
+ val DISPOSABLE = Disposer.newDisposable()
+
+ fun doTest(javaPath: String) {
+ try {
+ val fileContents = FileUtil.loadFile(File(javaPath), true)
+ val javaCoreEnvironment: JavaCoreProjectEnvironment = setUpJavaCoreEnvironment()
+ translateToKotlin(fileContents, javaCoreEnvironment.project)
+ }
+ finally {
+ Disposer.dispose(DISPOSABLE)
+ }
+ }
+
+ fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment {
+ // FIXME: There is no `Extensions.cleanRootArea` in 193 platform
+ // Extensions.cleanRootArea(DISPOSABLE)
+ val area = Extensions.getRootArea()
+
+ registerExtensionPoints(area)
+
+ val applicationEnvironment = JavaCoreApplicationEnvironment(DISPOSABLE)
+ val javaCoreEnvironment = object : JavaCoreProjectEnvironment(DISPOSABLE, applicationEnvironment) {
+ override fun preregisterServices() {
+ val projectArea = Extensions.getArea(project)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
+ }
+ }
+
+ javaCoreEnvironment.project.registerService(NullableNotNullManager::class.java, object : NullableNotNullManagerImpl(javaCoreEnvironment.project) {
+ override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
+ override fun isNotNull(owner: PsiModifierListOwner, checkBases: Boolean) = true
+ override fun hasHardcodedContracts(element: PsiElement): Boolean = false
+ override fun getNullables() = emptyList<String>()
+ override fun setNullables(vararg p0: String) = Unit
+ override fun getNotNulls() = emptyList<String>()
+ override fun setNotNulls(vararg p0: String) = Unit
+ override fun getDefaultNullable() = ""
+ override fun setDefaultNullable(defaultNullable: String) = Unit
+ override fun getDefaultNotNull() = ""
+ override fun setDefaultNotNull(p0: String) = Unit
+ override fun setInstrumentedNotNulls(p0: List<String>) = Unit
+ override fun getInstrumentedNotNulls() = emptyList<String>()
+ })
+
+ applicationEnvironment.application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
+
+ for (root in PathUtil.getJdkClassesRootsFromCurrentJre()) {
+ javaCoreEnvironment.addJarToClassPath(root)
+ }
+ val annotations: File? = findAnnotations()
+ if (annotations != null && annotations.exists()) {
+ javaCoreEnvironment.addJarToClassPath(annotations)
+ }
+ return javaCoreEnvironment
+ }
+
+ private fun registerExtensionPoints(area: ExtensionsArea) {
+ CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
+ }
+
+ fun findAnnotations(): File? {
+ var classLoader = JavaToKotlinTranslator::class.java.classLoader
+ while (classLoader != null) {
+ val loader = classLoader
+ if (loader is URLClassLoader) {
+ for (url in loader.urLs) {
+ if ("file" == url.protocol && url.file!!.endsWith("/annotations.jar")) {
+ return File(url.file!!)
+ }
+ }
+ }
+ classLoader = classLoader.parent
+ }
+ return null
+ }
+}
diff --git a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt
new file mode 100644
index 0000000..9a3dbe5
--- /dev/null
+++ b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.uast.kotlin.generate
+
+import com.intellij.lang.Language
+import com.intellij.openapi.diagnostic.logger
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiType
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
+import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
+import org.jetbrains.kotlin.idea.core.ShortenReferences
+import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
+import org.jetbrains.kotlin.idea.util.getResolutionScope
+import org.jetbrains.kotlin.idea.util.resolveToKotlinType
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.*
+import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
+import org.jetbrains.kotlin.utils.addToStdlib.cast
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
+import org.jetbrains.uast.*
+import org.jetbrains.uast.generate.UParameterInfo
+import org.jetbrains.uast.generate.UastCodeGenerationPlugin
+import org.jetbrains.uast.generate.UastElementFactory
+import org.jetbrains.uast.kotlin.*
+import org.jetbrains.uast.kotlin.internal.KotlinFakeUElement
+import org.jetbrains.uast.kotlin.internal.toSourcePsiFakeAware
+
+class KotlinUastCodeGenerationPlugin : UastCodeGenerationPlugin {
+ override val language: Language
+ get() = KotlinLanguage.INSTANCE
+
+ override fun getElementFactory(project: Project): UastElementFactory =
+ KotlinUastElementFactory(project)
+
+ override fun <T : UElement> replace(oldElement: UElement, newElement: T, elementType: Class<T>): T? {
+ val oldPsi = oldElement.toSourcePsiFakeAware().singleOrNull() ?: return null
+ val newPsi = newElement.sourcePsi?.let {
+ when {
+ it is KtCallExpression && it.parent is KtQualifiedExpression -> it.parent
+ else -> it
+ }
+ } ?: return null
+
+ val psiFactory = KtPsiFactory(oldPsi.project)
+ val oldParentPsi = oldPsi.parent
+ val (updOldPsi, updNewPsi) = when {
+ oldParentPsi is KtStringTemplateExpression && oldParentPsi.entries.size == 1 ->
+ oldParentPsi to newPsi
+
+ oldPsi is KtStringTemplateEntry && newPsi !is KtStringTemplateEntry && newPsi is KtExpression ->
+ oldPsi to psiFactory.createBlockStringTemplateEntry(newPsi)
+
+ oldPsi is KtBlockExpression && newPsi is KtBlockExpression -> {
+ if (!hasBraces(oldPsi) && hasBraces(newPsi)) {
+ oldPsi to psiFactory.createLambdaExpression("none", newPsi.statements.joinToString("\n") { "println()" }).bodyExpression!!.also {
+ it.statements.zip(newPsi.statements).forEach { it.first.replace(it.second) }
+ }
+ } else
+ oldPsi to newPsi
+ }
+
+ else ->
+ oldPsi to newPsi
+ }
+
+ return when (val replaced = updOldPsi.replace(updNewPsi)?.safeAs<KtElement>()?.let { ShortenReferences.DEFAULT.process(it) }) {
+ is KtCallExpression, is KtQualifiedExpression -> replaced.cast<KtExpression>().getPossiblyQualifiedCallExpression()
+ else -> replaced
+ }?.toUElementOfExpectedTypes(elementType)
+ }
+}
+
+private fun hasBraces(oldPsi: KtBlockExpression): Boolean = oldPsi.lBrace != null && oldPsi.rBrace != null
+
+class KotlinUastElementFactory(project: Project) : UastElementFactory {
+ private val psiFactory = KtPsiFactory(project)
+
+ @Deprecated("use version with context parameter")
+ override fun createQualifiedReference(qualifiedName: String, context: UElement?): UQualifiedReferenceExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createQualifiedReference(qualifiedName, context?.sourcePsi)
+ }
+
+ /*override*/ fun createQualifiedReference(qualifiedName: String, context: PsiElement?): UQualifiedReferenceExpression? {
+ return psiFactory.createExpression(qualifiedName).let {
+ when (it) {
+ is KtDotQualifiedExpression -> KotlinUQualifiedReferenceExpression(it, null)
+ is KtSafeQualifiedExpression -> KotlinUSafeQualifiedExpression(it, null)
+ else -> null
+ }
+
+ }
+ }
+
+ override fun createCallExpression(
+ receiver: UExpression?,
+ methodName: String,
+ parameters: List<UExpression>,
+ expectedReturnType: PsiType?,
+ kind: UastCallKind,
+ context: PsiElement?
+ ): UCallExpression? {
+ if (kind != UastCallKind.METHOD_CALL) return null
+
+ val typeParams = (context as? KtElement)?.let { kontext ->
+ val resolutionFacade = kontext.getResolutionFacade()
+ (expectedReturnType as? PsiClassType)?.parameters?.map { it.resolveToKotlinType(resolutionFacade) }
+ }
+
+ val name = methodName.quoteIfNeeded()
+ val methodCall = psiFactory.createExpression(
+ buildString {
+ if (receiver != null)
+ append("a.")
+ append(name)
+ if (typeParams != null) {
+ append(typeParams.joinToString(", ", "<", ">") { type ->
+ type.fqName?.asString() ?: ""
+ })
+ }
+ append("()")
+ }
+ ).getPossiblyQualifiedCallExpression() ?: return null
+
+ if (receiver != null) {
+ methodCall.parent.safeAs<KtDotQualifiedExpression>()?.receiverExpression?.replace(wrapULiteral(receiver).sourcePsi!!)
+ }
+
+ val valueArgumentList = methodCall.valueArgumentList
+ for (parameter in parameters) {
+ valueArgumentList?.addArgument(psiFactory.createArgument(wrapULiteral(parameter).sourcePsi as KtExpression))
+ }
+
+ return KotlinUFunctionCallExpression(methodCall, null)
+
+ }
+
+ override fun createStringLiteralExpression(text: String, context: PsiElement?): ULiteralExpression? {
+ return KotlinStringULiteralExpression(psiFactory.createExpression(StringUtil.wrapWithDoubleQuote(text)), null)
+ }
+
+ override fun createNullLiteral(context: PsiElement?): ULiteralExpression {
+ return psiFactory.createExpression("null").toUElementOfType<ULiteralExpression>()!!
+ }
+
+ /*override*/ fun createIntLiteral(value: Int, context: PsiElement?): ULiteralExpression {
+ return psiFactory.createExpression(value.toString()).toUElementOfType<ULiteralExpression>()!!
+ }
+
+ private fun KtExpression.ensureBlockExpressionBraces(): KtExpression {
+ if (this !is KtBlockExpression || hasBraces(this)) return this
+ val blockExpression = psiFactory.createBlock(this.statements.joinToString("\n") { "println()" })
+ for ((placeholder, statement) in blockExpression.statements.zip(this.statements)) {
+ placeholder.replace(statement)
+ }
+ return blockExpression
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createIfExpression(condition: UExpression, thenBranch: UExpression, elseBranch: UExpression?): UIfExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createIfExpression(condition, thenBranch, elseBranch, null)
+ }
+
+ override fun createIfExpression(
+ condition: UExpression,
+ thenBranch: UExpression,
+ elseBranch: UExpression?,
+ context: PsiElement?
+ ): UIfExpression? {
+ val conditionPsi = condition.sourcePsi as? KtExpression ?: return null
+ val thenBranchPsi = thenBranch.sourcePsi as? KtExpression ?: return null
+ val elseBranchPsi = elseBranch?.sourcePsi as? KtExpression
+
+ return KotlinUIfExpression(psiFactory.createIf(conditionPsi, thenBranchPsi.ensureBlockExpressionBraces(), elseBranchPsi?.ensureBlockExpressionBraces()), null)
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createParenthesizedExpression(expression: UExpression): UParenthesizedExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createParenthesizedExpression(expression, null)
+ }
+
+ override fun createParenthesizedExpression(expression: UExpression, context: PsiElement?): UParenthesizedExpression? {
+ val source = expression.sourcePsi ?: return null
+ val parenthesized = psiFactory.createExpression("(${source.text})") as? KtParenthesizedExpression ?: return null
+ return KotlinUParenthesizedExpression(parenthesized, null)
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createSimpleReference(name: String): USimpleNameReferenceExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createSimpleReference(name, null)
+ }
+
+ override fun createSimpleReference(name: String, context: PsiElement?): USimpleNameReferenceExpression? {
+ return KotlinUSimpleReferenceExpression(psiFactory.createSimpleName(name), null)
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createSimpleReference(variable: UVariable): USimpleNameReferenceExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createSimpleReference(variable, null)
+ }
+
+ override fun createSimpleReference(variable: UVariable, context: PsiElement?): USimpleNameReferenceExpression? {
+ return createSimpleReference(variable.name ?: return null, context)
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createReturnExpresion(expression: UExpression?, inLambda: Boolean): UReturnExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createReturnExpresion(expression, inLambda, null)
+ }
+
+ override fun createReturnExpresion(expression: UExpression?, inLambda: Boolean, context: PsiElement?): UReturnExpression? {
+ val label = if (inLambda && context != null) getParentLambdaLabelName(context)?.let { "@$it" } ?: "" else ""
+ val returnExpression = psiFactory.createExpression("return$label 1") as KtReturnExpression
+ val sourcePsi = expression?.sourcePsi
+ if (sourcePsi != null) {
+ returnExpression.returnedExpression!!.replace(sourcePsi)
+ } else {
+ returnExpression.returnedExpression?.delete()
+ }
+ return KotlinUReturnExpression(returnExpression, null)
+ }
+
+ private fun getParentLambdaLabelName(context: PsiElement): String? {
+ val lambdaExpression = context.getParentOfType<KtLambdaExpression>(false) ?: return null
+ lambdaExpression.parent.safeAs<KtLabeledExpression>()?.let { return it.getLabelName() }
+ val callExpression = lambdaExpression.getStrictParentOfType<KtCallExpression>() ?: return null
+ callExpression.valueArguments.find {
+ it.getArgumentExpression()?.unpackFunctionLiteral(allowParentheses = false) === lambdaExpression
+ } ?: return null
+ return callExpression.getCallNameExpression()?.text
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createBinaryExpression(
+ leftOperand: UExpression,
+ rightOperand: UExpression,
+ operator: UastBinaryOperator
+ ): UBinaryExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createBinaryExpression(leftOperand, rightOperand, operator, null)
+ }
+
+ override fun createBinaryExpression(
+ leftOperand: UExpression,
+ rightOperand: UExpression,
+ operator: UastBinaryOperator,
+ context: PsiElement?
+ ): UBinaryExpression? {
+ val binaryExpression = joinBinaryExpression(leftOperand, rightOperand, operator) ?: return null
+ return KotlinUBinaryExpression(binaryExpression, null)
+ }
+
+ private fun joinBinaryExpression(
+ leftOperand: UExpression,
+ rightOperand: UExpression,
+ operator: UastBinaryOperator
+ ): KtBinaryExpression? {
+ val leftPsi = leftOperand.sourcePsi ?: return null
+ val rightPsi = rightOperand.sourcePsi ?: return null
+
+ val binaryExpression = psiFactory.createExpression("a ${operator.text} b") as? KtBinaryExpression ?: return null
+ binaryExpression.left?.replace(leftPsi)
+ binaryExpression.right?.replace(rightPsi)
+ return binaryExpression
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createFlatBinaryExpression(
+ leftOperand: UExpression,
+ rightOperand: UExpression,
+ operator: UastBinaryOperator
+ ): UPolyadicExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createFlatBinaryExpression(leftOperand, rightOperand, operator, null)
+ }
+
+ override fun createFlatBinaryExpression(
+ leftOperand: UExpression,
+ rightOperand: UExpression,
+ operator: UastBinaryOperator,
+ context: PsiElement?
+ ): UPolyadicExpression? {
+
+ fun unwrapParentheses(exp: KtExpression?) {
+ if (exp !is KtParenthesizedExpression) return
+ if (!KtPsiUtil.areParenthesesUseless(exp)) return
+ exp.expression?.let { exp.replace(it) }
+ }
+
+ val binaryExpression = joinBinaryExpression(leftOperand, rightOperand, operator) ?: return null
+ unwrapParentheses(binaryExpression.left)
+ unwrapParentheses(binaryExpression.right)
+
+ return psiFactory.createExpression(binaryExpression.text).toUElementOfType()!!
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createBlockExpression(expressions: List<UExpression>): UBlockExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createBlockExpression(expressions, null)
+ }
+
+ override fun createBlockExpression(expressions: List<UExpression>, context: PsiElement?): UBlockExpression? {
+ val sourceExpressions = expressions.flatMap { it.toSourcePsiFakeAware() }
+ val block = psiFactory.createBlock(
+ sourceExpressions.joinToString(separator = "\n") { "println()" }
+ )
+ for ((placeholder, psiElement) in block.statements.zip(sourceExpressions)) {
+ placeholder.replace(psiElement)
+ }
+ return KotlinUBlockExpression(block, null)
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createDeclarationExpression(declarations: List<UDeclaration>): UDeclarationsExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createDeclarationExpression(declarations, null)
+ }
+
+ override fun createDeclarationExpression(declarations: List<UDeclaration>, context: PsiElement?): UDeclarationsExpression? {
+ return object : KotlinUDeclarationsExpression(null), KotlinFakeUElement {
+ override var declarations: List<UDeclaration> = declarations
+ override fun unwrapToSourcePsi(): List<PsiElement> = declarations.flatMap { it.toSourcePsiFakeAware() }
+ }
+ }
+
+ override fun createLambdaExpression(
+ parameters: List<UParameterInfo>,
+ body: UExpression,
+ context: PsiElement?
+ ): ULambdaExpression? {
+ val resolutionFacade = (context as? KtElement)?.getResolutionFacade()
+ val validator = (context as? KtElement)?.let { usedNamesFilter(it) } ?: { true }
+
+ val newLambdaStatements = if (body is UBlockExpression) {
+ body.expressions.flatMap { member ->
+ when {
+ member is UReturnExpression -> member.returnExpression?.toSourcePsiFakeAware().orEmpty()
+ else -> member.toSourcePsiFakeAware()
+ }
+ }
+ } else
+ listOf(body.sourcePsi!!)
+
+ val ktLambdaExpression = psiFactory.createLambdaExpression(
+ parameters.joinToString(", ") { p ->
+ val ktype = resolutionFacade?.let { p.type?.resolveToKotlinType(it) }
+ StringBuilder().apply {
+ append(p.suggestedName ?: ktype?.let { KotlinNameSuggester.suggestNamesByType(it, validator).firstOrNull() })
+ ?: KotlinNameSuggester.suggestNameByName("v", validator)
+ ktype?.fqName?.toString()?.let { append(": ").append(it) }
+ }
+ },
+ newLambdaStatements.joinToString("\n") { "placeholder" }
+ )
+
+ for ((old, new) in ktLambdaExpression.bodyExpression!!.statements.zip(newLambdaStatements)) {
+ old.replace(new)
+ }
+
+ return ktLambdaExpression.toUElementOfType()!!
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createLambdaExpression(parameters: List<UParameterInfo>, body: UExpression): ULambdaExpression? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createLambdaExpression(parameters, body, null)
+ }
+
+ override fun createLocalVariable(
+ suggestedName: String?,
+ type: PsiType?,
+ initializer: UExpression,
+ immutable: Boolean,
+ context: PsiElement?
+ ): ULocalVariable? {
+ val resolutionFacade = (context as? KtElement)?.getResolutionFacade()
+ val validator = (context as? KtElement)?.let { usedNamesFilter(it) } ?: { true }
+ val ktype = resolutionFacade?.let { type?.resolveToKotlinType(it) }
+
+ val function = psiFactory.createFunction(
+ buildString {
+ append("fun foo() { ")
+ append(if (immutable) "val" else "var")
+ append(" ")
+ append(suggestedName ?: ktype?.let { KotlinNameSuggester.suggestNamesByType(it, validator).firstOrNull() })
+ ?: KotlinNameSuggester.suggestNameByName("v", validator)
+ ktype?.fqName?.toString()?.let { append(": ").append(it) }
+ append(" = null")
+ append("}")
+ }
+ )
+
+ val ktVariable = PsiTreeUtil.findChildOfType(function, KtVariableDeclaration::class.java)!!
+ val newVariable = ktVariable.initializer!!.replace(initializer.sourcePsi!!).parent
+ return newVariable.toUElementOfType<UVariable>() as ULocalVariable
+ }
+
+ @Deprecated("use version with context parameter")
+ fun createLocalVariable(
+ suggestedName: String?,
+ type: PsiType?,
+ initializer: UExpression,
+ immutable: Boolean
+ ): ULocalVariable? {
+ logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
+ return createLocalVariable(suggestedName, type, initializer, immutable, null)
+ }
+}
+
+private fun usedNamesFilter(context: KtElement): (String) -> Boolean {
+ val scope = context.getResolutionScope()
+ return { name: String -> scope.findClassifier(Name.identifier(name), NoLookupLocation.FROM_IDE) == null }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt.193 b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/generate/KotlinUastCodeGenerationPlugin.kt.193
diff --git a/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt b/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt
new file mode 100644
index 0000000..022ab1e
--- /dev/null
+++ b/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt
@@ -0,0 +1,963 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.uast.test.kotlin
+
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.util.Key
+import com.intellij.openapi.util.Ref
+import com.intellij.psi.*
+import com.intellij.testFramework.LightProjectDescriptor
+import com.intellij.testFramework.UsefulTestCase
+import junit.framework.TestCase
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.utils.addToStdlib.cast
+import org.jetbrains.uast.*
+import org.jetbrains.uast.expressions.UInjectionHost
+import org.jetbrains.uast.generate.UParameterInfo
+import org.jetbrains.uast.generate.UastCodeGenerationPlugin
+import org.jetbrains.uast.generate.refreshed
+import org.jetbrains.uast.generate.replace
+import org.jetbrains.uast.kotlin.generate.KotlinUastElementFactory
+import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
+import org.jetbrains.uast.test.env.kotlin.findUElementByTextFromPsi
+import org.jetbrains.uast.visitor.UastVisitor
+import java.lang.StringBuilder
+import kotlin.test.fail as kfail
+
+class KotlinUastGenerationTest : KotlinLightCodeInsightFixtureTestCase() {
+
+ override fun getProjectDescriptor(): LightProjectDescriptor =
+ KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+
+ private val psiFactory
+ get() = KtPsiFactory(project)
+ private val generatePlugin: UastCodeGenerationPlugin
+ get() = UastCodeGenerationPlugin.byLanguage(KotlinLanguage.INSTANCE)!!
+ private val uastElementFactory
+ get() = generatePlugin.getElementFactory(myFixture.project) as KotlinUastElementFactory
+
+ fun `test logical and operation with simple operands`() {
+ val left = psiFactory.createExpression("true").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create left UExpression")
+ val right = psiFactory.createExpression("false").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create right UExpression")
+
+ val expression = uastElementFactory.createBinaryExpression(left, right, UastBinaryOperator.LOGICAL_AND, dummyContextFile())
+ ?: kfail("Cannot create expression")
+
+ TestCase.assertEquals("true && false", expression.sourcePsi?.text)
+ }
+
+ fun `test logical and operation with simple operands with parenthesis`() {
+ val left = psiFactory.createExpression("(true)").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create left UExpression")
+ val right = psiFactory.createExpression("(false)").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create right UExpression")
+
+ val expression = uastElementFactory.createFlatBinaryExpression(left, right, UastBinaryOperator.LOGICAL_AND, dummyContextFile())
+ ?: kfail("Cannot create expression")
+
+ TestCase.assertEquals("true && false", expression.sourcePsi?.text)
+ TestCase.assertEquals("""
+ UBinaryExpression (operator = &&)
+ ULiteralExpression (value = true)
+ ULiteralExpression (value = false)
+ """.trimIndent(), expression.putIntoFunctionBody().asRecursiveLogString().trim())
+ }
+
+ fun `test logical and operation with simple operands with parenthesis polyadic`() {
+ val left = psiFactory.createExpression("(true && false)").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create left UExpression")
+ val right = psiFactory.createExpression("(false)").toUElementOfType<UExpression>()
+ ?: kfail("Cannot create right UExpression")
+
+ val expression = uastElementFactory.createFlatBinaryExpression(left, right, UastBinaryOperator.LOGICAL_AND, dummyContextFile())
+ ?: kfail("Cannot create expression")
+
+ TestCase.assertEquals("true && false && false", expression.sourcePsi?.text)
+ TestCase.assertEquals("""
+ UBinaryExpression (operator = &&)
+ UBinaryExpression (operator = &&)
+ ULiteralExpression (value = null)
+ ULiteralExpression (value = null)
+ ULiteralExpression (value = null)
+ """.trimIndent(), expression.asRecursiveLogString().trim())
+ }
+
+ fun `test simple reference creating from variable`() {
+ val context = dummyContextFile()
+ val variable = uastElementFactory.createLocalVariable(
+ "a", PsiType.INT, uastElementFactory.createNullLiteral(context), false, context
+ ) ?: kfail("cannot create variable")
+
+ val reference = uastElementFactory.createSimpleReference(variable, context) ?: kfail("cannot create reference")
+ TestCase.assertEquals("a", reference.identifier)
+ }
+
+ fun `test simple reference by name`() {
+ val reference = uastElementFactory.createSimpleReference("a", dummyContextFile()) ?: kfail("cannot create reference")
+ TestCase.assertEquals("a", reference.identifier)
+ }
+
+ fun `test parenthesised expression`() {
+ val expression = psiFactory.createExpression("a + b").toUElementOfType<UExpression>()
+ ?: kfail("cannot create expression")
+ val parenthesizedExpression = uastElementFactory.createParenthesizedExpression(expression, dummyContextFile())
+ ?: kfail("cannot create parenthesized expression")
+
+ TestCase.assertEquals("(a + b)", parenthesizedExpression.sourcePsi?.text)
+ }
+
+ fun `test return expression`() {
+ val expression = psiFactory.createExpression("a + b").toUElementOfType<UExpression>()
+ ?: kfail("Cannot find plugin")
+
+ val returnExpression = uastElementFactory.createReturnExpresion(expression, false, dummyContextFile()) ?: kfail("cannot create return expression")
+ TestCase.assertEquals("a + b", returnExpression.returnExpression?.asRenderString())
+ TestCase.assertEquals("return a + b", returnExpression.sourcePsi?.text)
+ }
+
+ fun `test variable declaration without type`() {
+ val expression = psiFactory.createExpression("1 + 2").toUElementOfType<UExpression>()
+ ?: kfail("cannot create variable declaration")
+
+ val declaration = uastElementFactory.createLocalVariable("a", null, expression, false, dummyContextFile()) ?: kfail("cannot create variable")
+
+ TestCase.assertEquals("var a = 1 + 2", declaration.sourcePsi?.text)
+ }
+
+ fun `test variable declaration with type`() {
+ val expression = psiFactory.createExpression("b").toUElementOfType<UExpression>()
+ ?: kfail("cannot create variable declaration")
+
+ val declaration = uastElementFactory.createLocalVariable("a", PsiType.DOUBLE, expression, false, dummyContextFile()) ?: kfail("cannot create variable")
+
+ TestCase.assertEquals("var a: kotlin.Double = b", declaration.sourcePsi?.text)
+ }
+
+ fun `test final variable declaration`() {
+ val expression = psiFactory.createExpression("b").toUElementOfType<UExpression>()
+ ?: kfail("cannot create variable declaration")
+
+ val declaration = uastElementFactory.createLocalVariable("a", PsiType.DOUBLE, expression, true, dummyContextFile())
+ ?: kfail("cannot create variable")
+
+ TestCase.assertEquals("val a: kotlin.Double = b", declaration.sourcePsi?.text)
+ }
+
+ fun `test final variable declaration with unique name`() {
+ val expression = psiFactory.createExpression("b").toUElementOfType<UExpression>()
+ ?: kfail("cannot create variable declaration")
+
+ val declaration = uastElementFactory.createLocalVariable("a", PsiType.DOUBLE, expression, true, dummyContextFile())
+ ?: kfail("cannot create variable")
+
+ TestCase.assertEquals("val a: kotlin.Double = b", declaration.sourcePsi?.text)
+ TestCase.assertEquals("""
+ ULocalVariable (name = a)
+ USimpleNameReferenceExpression (identifier = b)
+ """.trimIndent(), declaration.asRecursiveLogString().trim())
+ }
+
+ fun `test block expression`() {
+ val statement1 = psiFactory.createExpression("System.out.println()").toUElementOfType<UExpression>()
+ ?: kfail("cannot create statement")
+ val statement2 = psiFactory.createExpression("System.out.println(2)").toUElementOfType<UExpression>()
+ ?: kfail("cannot create statement")
+
+ val block = uastElementFactory.createBlockExpression(listOf(statement1, statement2), dummyContextFile()) ?: kfail("cannot create block")
+
+ TestCase.assertEquals("""
+ {
+ System.out.println()
+ System.out.println(2)
+ }
+ """.trimIndent(), block.sourcePsi?.text
+ )
+ }
+
+ fun `test lambda expression`() {
+ val statement = psiFactory.createExpression("System.out.println()").toUElementOfType<UExpression>()
+ ?: kfail("cannot create statement")
+
+ val lambda = uastElementFactory.createLambdaExpression(
+ listOf(
+ UParameterInfo(PsiType.INT, "a"),
+ UParameterInfo(null, "b")
+ ),
+ statement,
+ dummyContextFile()
+ ) ?: kfail("cannot create lambda")
+
+ TestCase.assertEquals("{ a: kotlin.Int, b -> System.out.println() }", lambda.sourcePsi?.text)
+ TestCase.assertEquals("""
+ ULambdaExpression
+ UParameter (name = a)
+ UAnnotation (fqName = org.jetbrains.annotations.NotNull)
+ UParameter (name = b)
+ UAnnotation (fqName = null)
+ UBlockExpression
+ UQualifiedReferenceExpression
+ UQualifiedReferenceExpression
+ USimpleNameReferenceExpression (identifier = System)
+ USimpleNameReferenceExpression (identifier = out)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ """.trimIndent(), lambda.putIntoFunctionBody().asRecursiveLogString().trim())
+ }
+
+ private fun UExpression.putIntoFunctionBody(): UExpression {
+ val file = myFixture.configureByText("dummyFile.kt", "fun foo() { TODO() }") as KtFile
+ val ktFunction = file.declarations.single { it.name == "foo" } as KtFunction
+ val uMethod = ktFunction.toUElementOfType<UMethod>()!!
+ return runWriteCommand {
+ uMethod.uastBody.cast<UBlockExpression>().expressions.single().replace(this)!!
+ }
+ }
+
+ private fun <T : UExpression> T.putIntoVarInitializer(): T {
+ val file = myFixture.configureByText("dummyFile.kt", "val foo = TODO()") as KtFile
+ val ktFunction = file.declarations.single { it.name == "foo" } as KtProperty
+ val uMethod = ktFunction.toUElementOfType<UVariable>()!!
+ return runWriteCommand {
+ @Suppress("UNCHECKED_CAST")
+ generatePlugin.replace(uMethod.uastInitializer!!, this, UExpression::class.java) as T
+ }
+ }
+
+ private fun <T : UExpression> runWriteCommand(uExpression: () -> T): T {
+ val result = Ref<T>()
+ WriteCommandAction.runWriteCommandAction(project) {
+ result.set(uExpression())
+ }
+ return result.get()
+ }
+
+ fun `test lambda expression with explicit types`() {
+ val statement = psiFactory.createExpression("System.out.println()").toUElementOfType<UExpression>()
+ ?: kfail("cannot create statement")
+
+ val lambda = uastElementFactory.createLambdaExpression(
+ listOf(
+ UParameterInfo(PsiType.INT, "a"),
+ UParameterInfo(PsiType.DOUBLE, "b")
+ ),
+ statement,
+ dummyContextFile()
+ ) ?: kfail("cannot create lambda")
+
+ TestCase.assertEquals("{ a: kotlin.Int, b: kotlin.Double -> System.out.println() }", lambda.sourcePsi?.text)
+ TestCase.assertEquals("""
+ ULambdaExpression
+ UParameter (name = a)
+ UAnnotation (fqName = org.jetbrains.annotations.NotNull)
+ UParameter (name = b)
+ UAnnotation (fqName = org.jetbrains.annotations.NotNull)
+ UBlockExpression
+ UQualifiedReferenceExpression
+ UQualifiedReferenceExpression
+ USimpleNameReferenceExpression (identifier = System)
+ USimpleNameReferenceExpression (identifier = out)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ """.trimIndent(), lambda.putIntoFunctionBody().asRecursiveLogString().trim())
+ }
+
+ fun `test lambda expression with simplified block body with context`() {
+ val r = psiFactory.createExpression("return \"10\"").toUElementOfType<UExpression>()
+ ?: kfail("cannot create return")
+
+ val block = uastElementFactory.createBlockExpression(listOf(r), dummyContextFile()) ?: kfail("cannot create block")
+
+ val lambda = uastElementFactory.createLambdaExpression(listOf(UParameterInfo(null, "a")), block, dummyContextFile())
+ ?: kfail("cannot create lambda")
+ TestCase.assertEquals("""{ a -> "10" }""".trimMargin(), lambda.sourcePsi?.text)
+ TestCase.assertEquals("""
+ ULambdaExpression
+ UParameter (name = a)
+ UAnnotation (fqName = org.jetbrains.annotations.NotNull)
+ UBlockExpression
+ UReturnExpression
+ ULiteralExpression (value = "10")
+ """.trimIndent(), lambda.putIntoVarInitializer().asRecursiveLogString().trim())
+ }
+
+ fun `test function argument replacement`() {
+
+ val file = myFixture.configureByText(
+ "test.kt", """
+ fun f(a: Any){}
+
+ fun main(){
+ f(a)
+ }
+ """.trimIndent()
+ )
+
+ val expression = file.findUElementByTextFromPsi<UCallExpression>("f(a)")
+ val newArgument = psiFactory.createExpression("b").toUElementOfType<USimpleNameReferenceExpression>()
+ ?: kfail("cannot create reference")
+
+ WriteCommandAction.runWriteCommandAction(project) {
+ TestCase.assertNotNull(expression.valueArguments[0].replace(newArgument))
+ }
+
+ val updated = expression.refreshed() ?: kfail("cannot update expression")
+ TestCase.assertEquals("f", updated.methodName)
+ TestCase.assertTrue(updated.valueArguments[0] is USimpleNameReferenceExpression)
+ TestCase.assertEquals("b", (updated.valueArguments[0] as USimpleNameReferenceExpression).identifier)
+ TestCase.assertEquals("""
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (f))
+ USimpleNameReferenceExpression (identifier = f, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = b)
+ """.trimIndent(), updated.asRecursiveLogString().trim())
+ }
+
+ fun `test suggested name`() {
+ val expression = psiFactory.createExpression("f(a) + 1").toUElementOfType<UExpression>()
+ ?: kfail("cannot create expression")
+ val variable = uastElementFactory.createLocalVariable(null, PsiType.INT, expression, true, dummyContextFile())
+ ?: kfail("cannot create variable")
+
+ TestCase.assertEquals("val i: kotlin.Int = f(a) + 1", variable.sourcePsi?.text)
+ TestCase.assertEquals("""
+ ULocalVariable (name = i)
+ UBinaryExpression (operator = +)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (f))
+ USimpleNameReferenceExpression (identifier = <anonymous class>, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = a)
+ ULiteralExpression (value = null)
+ """.trimIndent(), variable.asRecursiveLogString().trim())
+ }
+
+ fun `test method call generation with receiver`() {
+ val receiver = psiFactory.createExpression(""""10"""").toUElementOfType<UExpression>()
+ ?: kfail("cannot create receiver")
+ val arg1 = psiFactory.createExpression("1").toUElementOfType<UExpression>()
+ ?: kfail("cannot create arg1")
+ val arg2 = psiFactory.createExpression("2").toUElementOfType<UExpression>()
+ ?: kfail("cannot create arg2")
+ val methodCall = uastElementFactory.createCallExpression(
+ receiver,
+ "substring",
+ listOf(arg1, arg2),
+ null,
+ UastCallKind.METHOD_CALL
+ ) ?: kfail("cannot create call")
+
+ TestCase.assertEquals(""""10".substring(1,2)""", methodCall.uastParent?.sourcePsi?.text)
+ TestCase.assertEquals("""
+ UQualifiedReferenceExpression
+ ULiteralExpression (value = "10")
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 2))
+ UIdentifier (Identifier (substring))
+ USimpleNameReferenceExpression (identifier = <anonymous class>, resolvesTo = null)
+ ULiteralExpression (value = null)
+ ULiteralExpression (value = null)
+ """.trimIndent(), methodCall.uastParent?.asRecursiveLogString()?.trim()
+ )
+ }
+
+ fun `test method call generation without receiver`() {
+ val arg1 = psiFactory.createExpression("1").toUElementOfType<UExpression>()
+ ?: kfail("cannot create arg1")
+ val arg2 = psiFactory.createExpression("2").toUElementOfType<UExpression>()
+ ?: kfail("cannot create arg2")
+ val methodCall = uastElementFactory.createCallExpression(
+ null,
+ "substring",
+ listOf(arg1, arg2),
+ null,
+ UastCallKind.METHOD_CALL
+ ) ?: kfail("cannot create call")
+
+ TestCase.assertEquals("""substring(1,2)""", methodCall.sourcePsi?.text)
+ }
+
+ fun `test method call generation with generics restoring`() {
+ val arrays = psiFactory.createExpression("java.util.Arrays").toUElementOfType<UExpression>()
+ ?: kfail("cannot create receiver")
+ val methodCall = uastElementFactory.createCallExpression(
+ arrays,
+ "asList",
+ listOf(),
+ createTypeFromText("java.util.List<java.lang.String>", null),
+ UastCallKind.METHOD_CALL,
+ dummyContextFile()
+ ) ?: kfail("cannot create call")
+ TestCase.assertEquals("java.util.Arrays.asList<kotlin.String>()", methodCall.uastParent?.sourcePsi?.text)
+ }
+
+ fun `test method call generation with generics restoring 2 parameters`() {
+ val collections = psiFactory.createExpression("java.util.Collections").toUElementOfType<UExpression>()
+ ?: kfail("cannot create receiver")
+ TestCase.assertEquals("java.util.Collections", collections.asRenderString())
+ val methodCall = uastElementFactory.createCallExpression(
+ collections,
+ "emptyMap",
+ listOf(),
+ createTypeFromText(
+ "java.util.Map<java.lang.String, java.lang.Integer>",
+ null
+ ),
+ UastCallKind.METHOD_CALL,
+ dummyContextFile()
+ ) ?: kfail("cannot create call")
+ TestCase.assertEquals("emptyMap<kotlin.String, kotlin.Int>()", methodCall.sourcePsi?.text)
+ TestCase.assertEquals("java.util.Collections.emptyMap<kotlin.String, kotlin.Int>()", methodCall.sourcePsi?.parent?.text)
+ TestCase.assertEquals(
+ """
+ UQualifiedReferenceExpression
+ UQualifiedReferenceExpression
+ UQualifiedReferenceExpression
+ USimpleNameReferenceExpression (identifier = java)
+ USimpleNameReferenceExpression (identifier = util)
+ USimpleNameReferenceExpression (identifier = Collections)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
+ UIdentifier (Identifier (emptyMap))
+ USimpleNameReferenceExpression (identifier = <anonymous class>, resolvesTo = null)
+ """.trimIndent(), methodCall.uastParent?.asRecursiveLogString()?.trim()
+ )
+ }
+
+ private fun dummyContextFile(): KtFile = myFixture.configureByText("file.kt", "fun foo() {}") as KtFile
+
+ fun `test method call generation with generics restoring 1 parameter with 1 existing`() {
+ val a = psiFactory.createExpression("A").toUElementOfType<UExpression>()
+ ?: kfail("cannot create a receiver")
+ val param = psiFactory.createExpression("\"a\"").toUElementOfType<UExpression>()
+ ?: kfail("cannot create a parameter")
+ val methodCall = uastElementFactory.createCallExpression(
+ a,
+ "kek",
+ listOf(param),
+ createTypeFromText(
+ "java.util.Map<java.lang.String, java.lang.Integer>",
+ null
+ ),
+ UastCallKind.METHOD_CALL,
+ dummyContextFile()
+ ) ?: kfail("cannot create call")
+
+ TestCase.assertEquals("A.kek<kotlin.String, kotlin.Int>(\"a\")", methodCall.sourcePsi?.parent?.text)
+ TestCase.assertEquals("""
+ UQualifiedReferenceExpression
+ USimpleNameReferenceExpression (identifier = A)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (kek))
+ USimpleNameReferenceExpression (identifier = <anonymous class>, resolvesTo = null)
+ ULiteralExpression (value = "a")
+ """.trimIndent(), methodCall.uastParent?.asRecursiveLogString()?.trim())
+ }
+
+
+ //not implemented (currently we dont perform resolve in code generating)
+ fun `ignore method call generation with generics restoring 1 parameter with 1 unused `() {
+ val aClassFile = myFixture.configureByText("A.kt",
+ """
+ object A {
+ fun <T1, T2, T3> kek(a: T1): Map<T1, T3> {
+ return TODO();
+ }
+ }
+ """.trimIndent()
+ )
+ val a = psiFactory.createExpression("A").toUElementOfType<UExpression>()
+ ?: kfail("cannot create a receiver")
+ val param = psiFactory.createExpression("\"a\"").toUElementOfType<UExpression>()
+ ?: kfail("cannot create a parameter")
+ val methodCall = uastElementFactory.createCallExpression(
+ a,
+ "kek",
+ listOf(param),
+ createTypeFromText(
+ "java.util.Map<java.lang.String, java.lang.Integer>",
+ null
+ ),
+ UastCallKind.METHOD_CALL,
+ aClassFile
+ ) ?: kfail("cannot create call")
+
+ TestCase.assertEquals("A.<String, Object, Integer>kek(\"a\")", methodCall.sourcePsi?.text)
+ }
+
+
+ fun `test method call generation with generics with context`() {
+ val file = myFixture.configureByText("file.kt", """
+ class A {
+ fun <T> method(): List<T> { TODO() }
+ }
+
+ fun main(){
+ val a = A()
+ println(a)
+ }
+ """.trimIndent()
+ ) as KtFile
+
+ val reference = file.findUElementByTextFromPsi<UElement>("println(a)")
+ .findElementByTextFromPsi<UReferenceExpression>("a")
+
+ val callExpression = uastElementFactory.createCallExpression(
+ reference,
+ "method",
+ emptyList(),
+ createTypeFromText(
+ "java.util.List<java.lang.Integer>",
+ null
+ ),
+ UastCallKind.METHOD_CALL,
+ context = reference.sourcePsi
+ ) ?: kfail("cannot create method call")
+
+ TestCase.assertEquals("a.method<kotlin.Int>()", callExpression.uastParent?.sourcePsi?.text)
+ TestCase.assertEquals("""
+ UQualifiedReferenceExpression
+ USimpleNameReferenceExpression (identifier = a)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
+ UIdentifier (Identifier (method))
+ USimpleNameReferenceExpression (identifier = <anonymous class>, resolvesTo = null)
+ """.trimIndent(), callExpression.uastParent?.asRecursiveLogString()?.trim()
+ )
+
+ }
+
+
+ fun `test replace lambda implicit return value`() {
+
+ val file = myFixture.configureByText(
+ "file.kt", """
+ fun main(){
+ val a: (Int) -> String = {
+ println(it)
+ println(2)
+ "abc"
+ }
+ }
+ """.trimIndent()
+ ) as KtFile
+
+ val uLambdaExpression = file.findUElementByTextFromPsi<UInjectionHost>("\"abc\"")
+ .getParentOfType<ULambdaExpression>() ?: kfail("cant get lambda")
+
+ val expressions = uLambdaExpression.body.cast<UBlockExpression>().expressions
+ UsefulTestCase.assertSize(3, expressions)
+
+ val uReturnExpression = expressions.last() as UReturnExpression
+ val newStringLiteral = uastElementFactory.createStringLiteralExpression("def", file) ?: kfail("cannot create method call")
+
+ val defReturn = runWriteCommand { uReturnExpression.replace(newStringLiteral) ?: kfail("cant replace") }
+ val uLambdaExpression2 = defReturn.getParentOfType<ULambdaExpression>() ?: kfail("cant get lambda")
+
+ TestCase.assertEquals("{\n println(it)\n println(2)\n \"def\"\n }", uLambdaExpression2.sourcePsi?.text)
+ TestCase.assertEquals(
+ """
+ ULambdaExpression
+ UParameter (name = it)
+ UBlockExpression
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = it)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ ULiteralExpression (value = 2)
+ UReturnExpression
+ ULiteralExpression (value = "def")
+ """.trimIndent(), uLambdaExpression2.asRecursiveLogString().trim()
+ )
+
+ }
+
+
+ private class UserDataChecker {
+
+ private val storedData = Any()
+ private val KEY = Key.create<Any>("testKey")
+
+ private lateinit var uniqueStringLiteralText: String
+
+ fun store(uElement: UInjectionHost) {
+ val psiElement = uElement.sourcePsi as KtStringTemplateExpression
+ uniqueStringLiteralText = psiElement.text
+ psiElement.putCopyableUserData(KEY, storedData)
+ }
+
+ fun checkUserDataAlive(uElement: UElement) {
+ val psiElements = uElement.let { SyntaxTraverser.psiTraverser(it.sourcePsi) }
+ .filter(KtStringTemplateExpression::class.java)
+ .filter { it.text == uniqueStringLiteralText }.toList()
+
+ UsefulTestCase.assertNotEmpty(psiElements)
+ UsefulTestCase.assertTrue("uElement still should keep the userdata", psiElements.any { storedData === it!!.getCopyableUserData(KEY) })
+ }
+
+ }
+
+ fun `test add intermediate returns to lambda`() {
+
+ val file = myFixture.configureByText(
+ "file.kt", """
+ fun main(){
+ val a: (Int) -> String = lname@{
+ println(it)
+ println(2)
+ "abc"
+ }
+ }
+ """.trimIndent()
+ ) as KtFile
+
+ val aliveChecker = UserDataChecker()
+ val uLambdaExpression = file.findUElementByTextFromPsi<UInjectionHost>("\"abc\"")
+ .also(aliveChecker::store)
+ .getParentOfType<ULambdaExpression>() ?: kfail("cant get lambda")
+
+ val oldBlockExpression = uLambdaExpression.body.cast<UBlockExpression>()
+ UsefulTestCase.assertSize(3, oldBlockExpression.expressions)
+
+ val conditionalExit = with(uastElementFactory) {
+ createIfExpression(
+ createBinaryExpression(
+ createSimpleReference("it", uLambdaExpression.sourcePsi)!!,
+ createIntLiteral(3, uLambdaExpression.sourcePsi),
+ UastBinaryOperator.GREATER,
+ uLambdaExpression.sourcePsi
+ )!!,
+ createReturnExpresion(
+ createStringLiteralExpression("exit", uLambdaExpression.sourcePsi)!!, true,
+ uLambdaExpression.sourcePsi
+ )!!,
+ null,
+ uLambdaExpression.sourcePsi
+ )!!
+ }
+
+ val newBlockExpression = uastElementFactory.createBlockExpression(
+ listOf(conditionalExit) + oldBlockExpression.expressions,
+ uLambdaExpression.sourcePsi
+ )!!
+
+ aliveChecker.checkUserDataAlive(newBlockExpression)
+
+ val uLambdaExpression2 = runWriteCommand {
+ oldBlockExpression.replace(newBlockExpression) ?: kfail("cant replace")
+ }.getParentOfType<ULambdaExpression>() ?: kfail("cant get lambda")
+
+ aliveChecker.checkUserDataAlive(uLambdaExpression2)
+
+ TestCase.assertEquals(
+ """
+ lname@{
+ if (it > 3) return@lname "exit"
+ println(it)
+ println(2)
+ "abc"
+ }
+ """.trimIndent(), uLambdaExpression2.sourcePsi?.parent?.text
+ )
+ TestCase.assertEquals(
+ """
+ ULambdaExpression
+ UParameter (name = it)
+ UBlockExpression
+ UIfExpression
+ UBinaryExpression (operator = >)
+ USimpleNameReferenceExpression (identifier = it)
+ ULiteralExpression (value = 3)
+ UReturnExpression
+ ULiteralExpression (value = "exit")
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = it)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ ULiteralExpression (value = 2)
+ UReturnExpression
+ ULiteralExpression (value = "abc")
+ """.trimIndent(), uLambdaExpression2.asRecursiveLogString().trim()
+ )
+
+ }
+
+ fun `test converting lambda to if`() {
+
+ val file = myFixture.configureByText(
+ "file.kt", """
+ fun foo(call: (Int) -> String): String = call.invoke(2)
+
+ fun main() {
+ foo {
+ println(it)
+ println(2)
+ "abc"
+ }
+ }
+ }
+ """.trimIndent()
+ ) as KtFile
+
+ val aliveChecker = UserDataChecker()
+ val uLambdaExpression = file.findUElementByTextFromPsi<UInjectionHost>("\"abc\"")
+ .also { aliveChecker.store(it) }
+ .getParentOfType<ULambdaExpression>() ?: kfail("cant get lambda")
+
+ val oldBlockExpression = uLambdaExpression.body.cast<UBlockExpression>()
+ aliveChecker.checkUserDataAlive(oldBlockExpression)
+
+ val newLambda = with(uastElementFactory) {
+ createLambdaExpression(
+ listOf(UParameterInfo(null, "it")),
+ createIfExpression(
+ createBinaryExpression(
+ createSimpleReference("it", uLambdaExpression.sourcePsi)!!,
+ createIntLiteral(3, uLambdaExpression.sourcePsi),
+ UastBinaryOperator.GREATER,
+ uLambdaExpression.sourcePsi
+ )!!,
+ oldBlockExpression,
+ createReturnExpresion(
+ createStringLiteralExpression("exit", uLambdaExpression.sourcePsi)!!, true,
+ uLambdaExpression.sourcePsi
+ )!!,
+ uLambdaExpression.sourcePsi
+ )!!.also {
+ aliveChecker.checkUserDataAlive(it)
+ },
+ uLambdaExpression.sourcePsi
+ )!!
+ }
+ aliveChecker.checkUserDataAlive(newLambda)
+
+ val uLambdaExpression2 = runWriteCommand {
+ uLambdaExpression.replace(newLambda) ?: kfail("cant replace")
+ }
+
+ TestCase.assertEquals(
+ """
+ { it ->
+ if (it > 3) {
+ println(it)
+ println(2)
+ "abc"
+ } else return@foo "exit"
+ }
+ """.trimIndent(), uLambdaExpression2.sourcePsi?.parent?.text
+ )
+ TestCase.assertEquals(
+ """
+ ULambdaExpression
+ UParameter (name = it)
+ UAnnotation (fqName = null)
+ UBlockExpression
+ UReturnExpression
+ UIfExpression
+ UBinaryExpression (operator = >)
+ USimpleNameReferenceExpression (identifier = it)
+ ULiteralExpression (value = 3)
+ UBlockExpression
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = it)
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ ULiteralExpression (value = 2)
+ ULiteralExpression (value = "abc")
+ UReturnExpression
+ ULiteralExpression (value = "exit")
+ """.trimIndent(), uLambdaExpression2.asRecursiveLogString().trim()
+ )
+ aliveChecker.checkUserDataAlive(uLambdaExpression2)
+
+ }
+
+ fun `test removing unnecessary type parameters while replace`() {
+ val aClassFile = myFixture.configureByText(
+ "A.kt",
+ """
+ class A {
+ fun <T> method():List<T> = TODO()
+ }
+ """.trimIndent()
+ )
+
+ val reference = psiFactory.createExpression("a")
+ .toUElementOfType<UReferenceExpression>() ?: kfail("cannot create reference expression")
+ val callExpression = uastElementFactory.createCallExpression(
+ reference,
+ "method",
+ emptyList(),
+ createTypeFromText(
+ "java.util.List<java.lang.Integer>",
+ null
+ ),
+ UastCallKind.METHOD_CALL,
+ context = aClassFile
+ ) ?: kfail("cannot create method call")
+
+ val listAssigment = myFixture.addFileToProject("temp.kt", """
+ fun foo(kek: List<Int>) {
+ val list: List<Int> = kek
+ }
+ """.trimIndent()).findUElementByTextFromPsi<UVariable>("val list: List<Int> = kek")
+
+ WriteCommandAction.runWriteCommandAction(project) {
+ val methodCall = listAssigment.uastInitializer?.replace(callExpression) ?: kfail("cannot replace!")
+ // originally result expected be `a.method()` but we expect to clean up type arguments in other plase
+ TestCase.assertEquals("a.method<Int>()", methodCall.sourcePsi?.parent?.text)
+ }
+
+ }
+
+ fun `test create if`() {
+ val condition = psiFactory.createExpression("true").toUElementOfType<UExpression>()
+ ?: kfail("cannot create condition")
+ val thenBranch = psiFactory.createBlock("{a(b);}").toUElementOfType<UExpression>()
+ ?: kfail("cannot create then branch")
+ val elseBranch = psiFactory.createExpression("c++").toUElementOfType<UExpression>()
+ ?: kfail("cannot create else branch")
+ val ifExpression = uastElementFactory.createIfExpression(condition, thenBranch, elseBranch, dummyContextFile())
+ ?: kfail("cannot create if expression")
+ TestCase.assertEquals("if (true) {\n { a(b); }\n } else c++", ifExpression.sourcePsi?.text)
+ }
+
+ fun `test qualified reference`() {
+ val reference = uastElementFactory.createQualifiedReference("java.util.List", myFixture.file)
+ TestCase.assertEquals("java.util.List", reference?.sourcePsi?.text)
+ }
+
+ fun `test build lambda from returning a variable`() {
+ val context = dummyContextFile()
+ val localVariable = uastElementFactory.createLocalVariable("a", null, uastElementFactory.createNullLiteral(context), true, context)
+ ?: kfail("cannot create variable")
+ val declarationExpression =
+ uastElementFactory.createDeclarationExpression(listOf(localVariable), context) ?: kfail("cannot create declaration expression")
+ val returnExpression = uastElementFactory.createReturnExpresion(
+ uastElementFactory.createSimpleReference(localVariable, context), false, context
+ ) ?: kfail("cannot create return expression")
+ val block = uastElementFactory.createBlockExpression(listOf(declarationExpression, returnExpression), context)
+ ?: kfail("cannot create block expression")
+
+ TestCase.assertEquals("""
+ UBlockExpression
+ UDeclarationsExpression
+ ULocalVariable (name = a)
+ ULiteralExpression (value = null)
+ UReturnExpression
+ USimpleNameReferenceExpression (identifier = a)
+ """.trimIndent(), block.asRecursiveLogString().trim())
+
+
+ val lambda = uastElementFactory.createLambdaExpression(listOf(), block, context) ?: kfail("cannot create lambda expression")
+ TestCase.assertEquals("{ val a = null\na }", lambda.sourcePsi?.text)
+
+ TestCase.assertEquals("""
+ ULambdaExpression
+ UBlockExpression
+ UDeclarationsExpression
+ ULocalVariable (name = a)
+ ULiteralExpression (value = null)
+ UReturnExpression
+ USimpleNameReferenceExpression (identifier = a)
+ """.trimIndent(), lambda.putIntoVarInitializer().asRecursiveLogString().trim())
+ }
+
+ fun `test expand oneline lambda`() {
+
+ val context = dummyContextFile()
+ val parameters = listOf(UParameterInfo(PsiType.INT, "a"))
+ val oneLineLambda = with(uastElementFactory) {
+ createLambdaExpression(
+ parameters,
+ createBinaryExpression(
+ createSimpleReference("a", context)!!,
+ createSimpleReference("a", context)!!,
+ UastBinaryOperator.PLUS, context
+ )!!, context
+ )!!
+ }.putIntoVarInitializer()
+
+ val lambdaReturn = (oneLineLambda.body as UBlockExpression).expressions.single()
+
+ val lambda = with(uastElementFactory) {
+ createLambdaExpression(
+ parameters,
+ createBlockExpression(
+ listOf(
+ createCallExpression(
+ null,
+ "println",
+ listOf(createSimpleReference("a", context)!!),
+ PsiType.VOID,
+ UastCallKind.METHOD_CALL,
+ context
+ )!!,
+ lambdaReturn
+ ),
+ context
+ )!!, context
+ )!!
+ }
+
+ TestCase.assertEquals("{ a: kotlin.Int -> println(a)\na + a }", lambda.sourcePsi?.text)
+
+ TestCase.assertEquals("""
+ ULambdaExpression
+ UParameter (name = a)
+ UAnnotation (fqName = org.jetbrains.annotations.NotNull)
+ UBlockExpression
+ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
+ UIdentifier (Identifier (println))
+ USimpleNameReferenceExpression (identifier = println, resolvesTo = null)
+ USimpleNameReferenceExpression (identifier = a)
+ UReturnExpression
+ UBinaryExpression (operator = +)
+ USimpleNameReferenceExpression (identifier = a)
+ USimpleNameReferenceExpression (identifier = a)
+ """.trimIndent(), lambda.putIntoVarInitializer().asRecursiveLogString().trim())
+ }
+
+ private fun createTypeFromText(s: String, newClass: PsiElement?): PsiType? {
+ return JavaPsiFacade.getElementFactory(myFixture.project).createTypeFromText(s, newClass)
+ }
+
+}
+
+// it is a copy of org.jetbrains.uast.UastUtils.asRecursiveLogString with `appendLine` instead of `appendln` to avoid windows related issues
+private fun UElement.asRecursiveLogString(render: (UElement) -> String = { it.asLogString() }): String {
+ val stringBuilder = StringBuilder()
+ val indent = " "
+
+ accept(object : UastVisitor {
+ private var level = 0
+
+ override fun visitElement(node: UElement): Boolean {
+ stringBuilder.append(indent.repeat(level))
+ stringBuilder.appendLine(render(node))
+ level++
+ return false
+ }
+
+ override fun afterVisitElement(node: UElement) {
+ super.afterVisitElement(node)
+ level--
+ }
+ })
+ return stringBuilder.toString()
+}
diff --git a/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt.193 b/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/uast-kotlin/tests/KotlinUastGenerationTest.kt.193
diff --git a/tests/mute-platform.csv b/tests/mute-platform.csv
index f43f7c1..3f9b26e 100644
--- a/tests/mute-platform.csv
+++ b/tests/mute-platform.csv
@@ -2,15 +2,45 @@
org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryClassUsages, KT-34542, FAIL,
org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryNestedClassUsages, KT-34542, FAIL,
org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryObjectUsages, KT-34542, FAIL,
+"org.jetbrains.kotlin.gradle.HierarchicalMultiplatformProjectImportingTest.testJvmWithJavaOnHMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", No module dependency found,,
+"org.jetbrains.kotlin.gradle.HierarchicalMultiplatformProjectImportingTest.testJvmWithJavaOnHMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", No module dependency found,,
org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.simpleAndroidAppWithCommonModule, KT-35225,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[0: Gradle-4.9, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[2: Gradle-5.6.4, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testJsTestOutputFileInProjectWithAndroid[0: Gradle-4.9, KotlinGradlePlugin-minimal]", NPE - no facet configured,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testJsTestOutputFileInProjectWithAndroid[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", NPE - no facet configured,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testJsTestOutputFileInProjectWithAndroid[2: Gradle-5.6.4, KotlinGradlePlugin-minimal]", NPE - no facet configured,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testJsTestOutputFileInProjectWithAndroid[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", NPE - no facet configured,,
org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithAndroid, KT-35225,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[0: Gradle-4.9, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[2: Gradle-5.6.4, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[0: Gradle-4.9, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[2: Gradle-5.6.4, KotlinGradlePlugin-minimal]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDependencyOnRoot[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDependencyOnRoot[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testImportBeforeBuild[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testImportBeforeBuild[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJavaTransitiveOnMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJavaTransitiveOnMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJvmWithJava[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJvmWithJava[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testNestedDependencies[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testNestedDependencies[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testProjectDependency[1: Gradle-4.9, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
+"org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testProjectDependency[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable]", Gradle Tests in 201,,
org.jetbrains.kotlin.idea.caches.resolve.MultiModuleLineMarkerTestGenerated.testKotlinTestAnnotations, No line markers for test run,,
org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testAndroidIllegalIdentifiers_inspectionData_Inspections_test, Unprocessed,,
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testAndroidGradleJsDetection, NPE during import,,
org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testTwoClasses,,, FLAKY
org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValAndClass,,, FLAKY
org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValOrder,,, FLAKY
org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Val.testValWithTypeWoInitializer,,, FLAKY
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed,, FLAKY
org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Common.StaticMembers.testJavaStaticMethodsFromImports, KT-32919,,
org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast1, KT-32919,,
org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast2, KT-32919,,
@@ -68,8 +98,6 @@
org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression3, KT-34672, FAIL,
org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterPrimaryConstructor, on ConvertFunctionTypeParameterToReceiver rerun,, FLAKY
org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterSecondaryConstructor, on ConvertFunctionTypeParameterToReceiver rerun,, FLAKY
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder,, FLAKY
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered,, FLAKY
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testBlankLineBetween, KT-34408,,
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit, KT-34408,,
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit2, KT-34408,,
@@ -91,23 +119,76 @@
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testIf, KT-34408,,
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testNotSingleLineStatement, KT-34408,,
org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testWhenEntry, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder,, FLAKY
org.jetbrains.kotlin.idea.navigation.KotlinGotoImplementationMultiModuleTestGenerated.testExpectClassSuperclassFun,,, FLAKY
org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib1.testUseJavaFromLib, KT-34542, FAIL,
org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib2.testUseJavaSAMFromLib, KT-34542, FAIL,
org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib3.testUseJavaSAMFromLib, KT-34542, FAIL,
org.jetbrains.kotlin.idea.quickfix.QuickFixMultiFileTestGenerated.ChangeSignature.Jk.testJkKeepValOnParameterTypeChange, Unprocessed,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.AddMissingActualMembers.testClassFunctionWithIncompatibleConstructor, Range must be inside element being annotated,,
org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertActualSealedClassToEnum, Enum reorder,,
org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertExpectSealedClassToEnum, Enum reorder,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.CreateFromUsage.CreateSecondaryConstructor.testNoneApplicable, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertSuper, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertSuper, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertThis, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertThis, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableOnEmpty, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableOnEmpty, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableWithOneConstructor, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableWithOneConstructor, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredNoSuper, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredNoSuper, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredParameterless, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredParameterless, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithBody, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithBody, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithParameter, Range must be inside element being annotated,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithParameter, Range must be inside element being annotated,,
org.jetbrains.kotlin.idea.refactoring.inline.InlineTestGenerated.Function.ExpressionBody.testMultipleInExpression, Unstable order of usages,,FLAKY
+org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed,, FLAKY
org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda, final modifier added,,
org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance, final modifier added,,
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename,, FLAKY
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.test1, Additional signature,,
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImport, Additional signature,,
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImportWithBlankLineInsertion, Additional signature,,
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImportWithBlankLinesRemoval, Additional signature,,
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testCommentTyping, Additional signature,,
org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedExtension, KT-34825,,
org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testInLibrarySource, KT-34542, FAIL,
org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToFunParameter, KT-34542, FAIL,
org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToLocalFun, KT-34542, FAIL,
-org.jetbrains.uast.test.kotlin.KotlinUastReferencesTest.`test original getter is visible when reference is under renaming`, Extensions API changed,,
-org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed,, FLAKY
-org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, fail on TeamCity but works well locally,, FLAKY
+org.jetbrains.kotlin.idea.slicer.SlicerTreeTestGenerated.testInflow_SecondaryConstructorParameter, IDEA-234737 element.parent must not be null,,
+org.jetbrains.kotlin.idea.slicer.SlicerTreeTestGenerated.testInflow_SecondaryConstructorParameterWithDefault, IDEA-234737 element.parent must not be null,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testAnnotationArgBySpELRefInXMLConf_AnnotationArgBySpELRefInXMLConf, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testAnnotationArgBySpELRefInXMLConf_AnnotationArgBySpELRefInXMLConf, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testIsPropertyWithXmlRefsBySpelRef_IsPropertyWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testIsPropertyWithXmlRefsBySpelRef_IsPropertyWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToJavaAnnotated_JavaSpelRefToJavaAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToJavaAnnotated_JavaSpelRefToJavaAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToJava_JavaSpelRefToJava, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToJava_JavaSpelRefToJava, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToKtAnnotated_JavaSpelRefToKtAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToKtAnnotated_JavaSpelRefToKtAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToKt_JavaSpelRefToKt, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testJavaSpelRefToKt_JavaSpelRefToKt, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToJavaAnnotated_KtSpelRefToJavaAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToJavaAnnotated_KtSpelRefToJavaAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToJava_KtSpelRefToJava, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToJava_KtSpelRefToJava, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToKtAnnotated_KtSpelRefToKtAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToKtAnnotated_KtSpelRefToKtAnnotated, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToKt_KtSpelRefToKt, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testKtSpelRefToKt_KtSpelRefToKt, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testParameterWithXmlRefsBySpelRef_ParameterWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testParameterWithXmlRefsBySpelRef_ParameterWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testPropertyWithXmlRefsBySpelRef_PropertyWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.idea.spring.tests.rename.SpringRenameTestGenerated.testPropertyWithXmlRefsBySpelRef_PropertyWithXmlRefBySpelRef, Rename failed in Spring,,
+org.jetbrains.kotlin.jps.build.IncrementalConstantSearchTest.testJavaConstantChangedUsedInKotlin, Incremental compilation in 201,,
+org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.WithJava.JavaUsedInKotlin.testConstantChanged, Incremental compilation in 201,,
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed,, FLAKY
org.jetbrains.kotlin.idea.refactoring.pullUp.PullUpTestGenerated.K2K.testAccidentalOverrides, Unprocessed,, FLAKY
-org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename,, FLAKY
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder,, FLAKY
\ No newline at end of file
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, fail on TeamCity but works well locally,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder,, FLAKY
\ No newline at end of file
diff --git a/tests/mute-platform.csv.193 b/tests/mute-platform.csv.193
new file mode 100644
index 0000000..f43f7c1
--- /dev/null
+++ b/tests/mute-platform.csv.193
@@ -0,0 +1,113 @@
+Test key, Issue, State (optional: MUTE or FAIL), Status (optional: FLAKY)
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryClassUsages, KT-34542, FAIL,
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryNestedClassUsages, KT-34542, FAIL,
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryObjectUsages, KT-34542, FAIL,
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.simpleAndroidAppWithCommonModule, KT-35225,,
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithAndroid, KT-35225,,
+org.jetbrains.kotlin.idea.caches.resolve.MultiModuleLineMarkerTestGenerated.testKotlinTestAnnotations, No line markers for test run,,
+org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testAndroidIllegalIdentifiers_inspectionData_Inspections_test, Unprocessed,,
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testTwoClasses,,, FLAKY
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValAndClass,,, FLAKY
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValOrder,,, FLAKY
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Val.testValWithTypeWoInitializer,,, FLAKY
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed,, FLAKY
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Common.StaticMembers.testJavaStaticMethodsFromImports, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast1, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast2, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties1, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties2, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testNullableReceiver, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSafeCall, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast2, KT-32919,,
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSyntheticExtensions1, KT-32919,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromJSLibrarySourcesTest.testIcon, Unprocessed,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testBuiltinClass, KT-34542,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testJdkClass, KT-34542,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testLightClassForLibrarySource, KT-34542,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testOurKotlinClass, KT-34542,,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testClassObject, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testConstructor, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testEnum, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionFunction, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalFunction, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testNamedObject, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testSameNameInDifferentSources, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeAlias, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeWithSameShortName, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testClassObject, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testConstructor, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testEnum, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionFunction, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalFunction, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testNamedObject, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testProperty, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testSameNameInDifferentSources, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeAlias, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeWithSameShortName, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunCallInLibrary, Unprocessed,,
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunInnerClassFromLibrary, Unprocessed,,
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testCoroutineContextCheck, KT-34659,,
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testDispatchersTypeDetection, KT-34659,,
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testLambdaReceiverType, KT-34659,,
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testNestedFunctionsInsideSuspendLambda, KT-34659,,
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testSimpleCoroutineScope, KT-34659,,
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression, KT-34672, FAIL,
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression2, KT-34672, FAIL,
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression3, KT-34672, FAIL,
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterPrimaryConstructor, on ConvertFunctionTypeParameterToReceiver rerun,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterSecondaryConstructor, on ConvertFunctionTypeParameterToReceiver rerun,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered,, FLAKY
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testBlankLineBetween, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testPropertyWithAnnotation, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks3, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons3, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType2, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.NestedIfs.testBlockBody, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testFunctionWithOneLineReturn, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testIf, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testNotSingleLineStatement, KT-34408,,
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testWhenEntry, KT-34408,,
+org.jetbrains.kotlin.idea.navigation.KotlinGotoImplementationMultiModuleTestGenerated.testExpectClassSuperclassFun,,, FLAKY
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib1.testUseJavaFromLib, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib2.testUseJavaSAMFromLib, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib3.testUseJavaSAMFromLib, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiFileTestGenerated.ChangeSignature.Jk.testJkKeepValOnParameterTypeChange, Unprocessed,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertActualSealedClassToEnum, Enum reorder,,
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertExpectSealedClassToEnum, Enum reorder,,
+org.jetbrains.kotlin.idea.refactoring.inline.InlineTestGenerated.Function.ExpressionBody.testMultipleInExpression, Unstable order of usages,,FLAKY
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda, final modifier added,,
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance, final modifier added,,
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedExtension, KT-34825,,
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testInLibrarySource, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToFunParameter, KT-34542, FAIL,
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToLocalFun, KT-34542, FAIL,
+org.jetbrains.uast.test.kotlin.KotlinUastReferencesTest.`test original getter is visible when reference is under renaming`, Extensions API changed,,
+org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed,, FLAKY
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, fail on TeamCity but works well locally,, FLAKY
+org.jetbrains.kotlin.idea.refactoring.pullUp.PullUpTestGenerated.K2K.testAccidentalOverrides, Unprocessed,, FLAKY
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename,, FLAKY
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder,, FLAKY
\ No newline at end of file