Compare commits

..

6 Commits

Author SHA1 Message Date
Nicolay Mitropolsky
4a4eee7b36 JavaClassifierTypeImpl.resolutionResult dropped 2020-06-18 10:34:22 +03:00
Ilya Gorbunov
e13a38a758 Fix OnlyInputType usage in tests where it can be invisible 2020-06-18 09:34:13 +03:00
Jinseong Jeon
9e9ca4953f FIR2IR: coerce to Unit when "when" expr is not effectively exhaustive 2020-06-18 09:23:32 +03:00
Vladimir Ilmov
62dcfcde79 (CoroutineDebugger) -core jar has precedence over -debug
#KT-39412 fixed
 #KT-39648 fixed
2020-06-17 23:48:09 +02:00
Dmitry Petrov
4739adb6dc KT-36992 Do not generate annotations on synthetic accessors
Also, do not generate nullability annotations on synthetic methods.
2020-06-17 23:54:51 +03:00
Steven Schäfer
03651f1dd4 IR: Fix inner class type parameters in IrTypeSystemContext 2020-06-17 22:10:00 +03:00
271 changed files with 1973 additions and 10169 deletions

8
.bunch
View File

@@ -1,3 +1,7 @@
202
193
201
193_201
202_201
192
as36_192
as40
as41_201

View File

@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.incremental.storage
import com.intellij.util.io.DataExternalizer
import com.intellij.util.io.KeyDescriptor
import com.intellij.util.io.PersistentHashMap
import com.intellij.util.io.JpsPersistentHashMap
import java.io.File
@@ -28,10 +28,10 @@ class NonCachingLazyStorage<K, V>(
private val valueExternalizer: DataExternalizer<V>
) : LazyStorage<K, V> {
@Volatile
private var storage: PersistentHashMap<K, V>? = null
private var storage: JpsPersistentHashMap<K, V>? = null
@Synchronized
private fun getStorageIfExists(): PersistentHashMap<K, V>? {
private fun getStorageIfExists(): JpsPersistentHashMap<K, V>? {
if (storage != null) return storage
if (storageFile.exists()) {
@@ -43,7 +43,7 @@ class NonCachingLazyStorage<K, V>(
}
@Synchronized
private fun getStorageOrCreateNew(): PersistentHashMap<K, V> {
private fun getStorageOrCreateNew(): JpsPersistentHashMap<K, V> {
if (storage == null) {
storage = createMap()
}
@@ -69,7 +69,7 @@ class NonCachingLazyStorage<K, V>(
}
override fun append(key: K, value: V) {
getStorageOrCreateNew().appendData(key) { dataOutput -> valueExternalizer.save(dataOutput, value) }
getStorageOrCreateNew().appendDataWithoutCache(key, value)
}
@Synchronized
@@ -79,7 +79,7 @@ class NonCachingLazyStorage<K, V>(
} catch (ignored: Throwable) {
}
PersistentHashMap.deleteFilesStartingWith(storageFile)
JpsPersistentHashMap.deleteFilesStartingWith(storageFile)
storage = null
}
@@ -101,6 +101,6 @@ class NonCachingLazyStorage<K, V>(
storage?.close()
}
private fun createMap(): PersistentHashMap<K, V> =
PersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
private fun createMap(): JpsPersistentHashMap<K, V> =
JpsPersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.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)
}

View File

@@ -8,4 +8,4 @@ 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>>
typealias SourceFrames = Array<Frame<SourceValue>?>

View File

@@ -8,4 +8,4 @@ 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>?>
typealias SourceFrames = Array<Frame<SourceValue>>

View File

@@ -8,4 +8,4 @@ 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>>
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>

View File

@@ -8,4 +8,4 @@ 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>?>
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>>

View File

@@ -5,4 +5,4 @@
package org.jetbrains.kotlin.codegen.state
typealias JvmMethodExceptionTypes = Array<out String?>?
typealias JvmMethodExceptionTypes = Array<out String>?

View File

@@ -5,4 +5,4 @@
package org.jetbrains.kotlin.codegen.state
typealias JvmMethodExceptionTypes = Array<out String>?
typealias JvmMethodExceptionTypes = Array<out String?>?

View File

@@ -31,6 +31,6 @@ interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render,
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
)
}

View File

@@ -31,6 +31,6 @@ interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
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))
)
}

View File

@@ -17,6 +17,8 @@
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;
@@ -30,25 +32,31 @@ public class MessageUtil {
private MessageUtil() {}
@Nullable
public static CompilerMessageLocation psiElementToMessageLocation(@Nullable PsiElement element) {
public static CompilerMessageSourceLocation psiElementToMessageLocation(@Nullable PsiElement element) {
if (element == null) return null;
PsiFile file = element.getContainingFile();
return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnInPsiFile(file, element.getTextRange()));
return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnRangeInPsiFile(file, element.getTextRange()));
}
@Nullable
public static CompilerMessageLocation psiFileToMessageLocation(
public static CompilerMessageSourceLocation psiFileToMessageLocation(
@NotNull PsiFile file,
@Nullable String defaultValue,
@NotNull PsiDiagnosticUtils.LineAndColumn lineAndColumn
@NotNull PsiDiagnosticUtils.LineAndColumnRange range
) {
VirtualFile virtualFile = file.getVirtualFile();
String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
return CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn(), lineAndColumn.getLineContent());
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) {
return toSystemDependentName(virtualFile.getPath());
// 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();
}
}

View File

@@ -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 @@ public class MessageUtil {
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());
}
}

View File

@@ -4,52 +4,147 @@
*/
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.JavaCoreApplicationEnvironment;
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.FileContextProvider;
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;
public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
registerExtensionPoints();
return environment;
}
/**
* 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 {
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
super(parentDisposable, unitTestMode);
}
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
}
private static void registerExtensionPoints() {
registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
super(parentDisposable, unitTestMode);
registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
registerExtensionPoints();
registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
registerApplicationExtensionPoint(ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
registerExtensions();
}
registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
private void registerExtensionPoints() {
ExtensionsArea area = Extensions.getRootArea();
IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
}
CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
@Nullable
@Override
protected VirtualFileSystem createJrtFileSystem() {
return new CoreJrtFileSystem();
}
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();
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.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();
}
}

View File

@@ -22,7 +22,6 @@ import com.intellij.psi.*
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

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.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()
}

View File

@@ -6,10 +6,4 @@
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")
}

View File

@@ -1,9 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler
fun setupIdeaStandaloneExecution() {
}

View File

@@ -8,11 +8,9 @@ package org.jetbrains.kotlin.cli.jvm.compiler
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(pluginRoot, fileName, area)
CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginFile, fileName, area)
}

View File

@@ -1,16 +0,0 @@
/*
* 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)
}

View File

@@ -581,11 +581,15 @@ class Fir2IrVisitor(
KtNodeTypes.POSTFIX_EXPRESSION -> IrStatementOrigin.EXCLEXCL
else -> null
}
// If the constant true branch has empty body, it won't be converted. Thus, the entire `when` expression is effectively _not_
// exhaustive anymore. In that case, coerce the return type of `when` expression to Unit as per the backend expectation.
val effectivelyNotExhaustive = !whenExpression.isExhaustive ||
whenExpression.branches.any { it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty() }
return conversionScope.withWhenSubject(subjectVariable) {
whenExpression.convertWithOffsets { startOffset, endOffset ->
val irWhen = IrWhenImpl(
startOffset, endOffset,
whenExpression.typeRef.toIrType(),
if (effectivelyNotExhaustive) irBuiltIns.unitType else whenExpression.typeRef.toIrType(),
origin
).apply {
var unconditionalBranchFound = false

View File

@@ -14130,6 +14130,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/innerNested/innerGenericClassFromJava.kt");
}
@TestMetadata("innerImplicitParameter.kt")
public void testInnerImplicitParameter() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerImplicitParameter.kt");
}
@TestMetadata("innerJavaClass.kt")
public void testInnerJavaClass() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerJavaClass.kt");

View File

@@ -24,8 +24,6 @@ import java.util.ArrayList
class JavaClassifierTypeImpl(psiClassType: PsiClassType) : JavaTypeImpl<PsiClassType>(psiClassType), JavaClassifierType {
private var resolutionResult: ResolutionResult? = null
override val classifier: JavaClassifierImpl<*>?
get() = resolve().classifier
@@ -65,15 +63,13 @@ class JavaClassifierTypeImpl(psiClassType: PsiClassType) : JavaTypeImpl<PsiClass
)
private fun resolve(): ResolutionResult {
return resolutionResult ?: run {
return run {
val result = psi.resolveGenerics()
val psiClass = result.element
val substitutor = result.substitutor
ResolutionResult(
psiClass?.let { JavaClassifierImpl.create(it) }, substitutor, PsiClassType.isRaw(result)
).apply {
resolutionResult = this
}
)
}
}

View File

@@ -18,6 +18,8 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
object LAMBDA_IMPL : IrDeclarationOriginImpl("LAMBDA_IMPL")
object FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL", isSynthetic = true)
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true)
object SYNTHETIC_ACCESSOR_FOR_HIDDEN_CONSTRUCTOR :
IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR_FOR_HIDDEN_CONSTRUCTOR", isSynthetic = true)
object SYNTHETIC_MARKER_PARAMETER : IrDeclarationOriginImpl("SYNTHETIC_MARKER_PARAMETER", isSynthetic = true)
object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY")
object JVM_STATIC_WRAPPER : IrDeclarationOriginImpl("JVM_STATIC_WRAPPER")

View File

@@ -277,12 +277,15 @@ abstract class AnnotationCodegen(
companion object {
private fun isInvisibleFromTheOutside(declaration: IrDeclaration?): Boolean {
if (declaration is IrSimpleFunction && declaration.origin === JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) {
if (declaration is IrSimpleFunction && declaration.origin.isSynthetic) {
return true
}
if (declaration is IrDeclarationWithVisibility) {
return !declaration.visibility.isVisibleOutside()
}
if (declaration is IrValueParameter && (declaration.parent as IrDeclaration).origin.isSynthetic) {
return true
}
return false
}

View File

@@ -130,6 +130,7 @@ internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspen
origin != JvmLoweredDeclarationOrigin.JVM_OVERLOADS_WRAPPER &&
origin != JvmLoweredDeclarationOrigin.MULTIFILE_BRIDGE &&
origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR &&
origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR_FOR_HIDDEN_CONSTRUCTOR &&
origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE &&
origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC &&
origin != IrDeclarationOrigin.BRIDGE &&

View File

@@ -69,7 +69,9 @@ class FunctionCodegen(
generateParameterNames(irFunction, methodVisitor, signature, context.state)
}
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER &&
irFunction.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
) {
object : AnnotationCodegen(classCodegen, context) {
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
return methodVisitor.visitAnnotation(descr, visible)

View File

@@ -217,12 +217,13 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
get() = this in context.hiddenConstructors || (
!Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters &&
origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER &&
origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR)
origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR &&
origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR_FOR_HIDDEN_CONSTRUCTOR)
private fun handleHiddenConstructor(declaration: IrConstructor): IrConstructorImpl {
require(declaration.isOrShouldBeHidden, declaration::render)
return context.hiddenConstructors.getOrPut(declaration) {
declaration.makeConstructorAccessor().also { accessor ->
declaration.makeConstructorAccessor(JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR_FOR_HIDDEN_CONSTRUCTOR).also { accessor ->
// There's a special case in the JVM backend for serializing the metadata of hidden
// constructors - we serialize the descriptor of the original constructor, but the
// signature of the accessor. We implement this special case in the JVM IR backend by
@@ -249,11 +250,14 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
candidates.lastOrNull { parent is IrClass && it.isSubclassOf(parent) } ?: classes.last()
} else parent
private fun IrConstructor.makeConstructorAccessor(): IrConstructorImpl {
private fun IrConstructor.makeConstructorAccessor(
originForConstructorAccessor: IrDeclarationOrigin =
JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
): IrConstructorImpl {
val source = this
return buildConstructor {
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
origin = originForConstructorAccessor
name = source.name
visibility = Visibilities.PUBLIC
}.also { accessor ->

View File

@@ -112,7 +112,7 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
private fun getTypeParameters(typeConstructor: TypeConstructorMarker): List<IrTypeParameter> {
return when (typeConstructor) {
is IrTypeParameterSymbol -> emptyList()
is IrClassSymbol -> typeConstructor.owner.typeParameters
is IrClassSymbol -> extractTypeParameters(typeConstructor.owner)
else -> error("unsupported type constructor")
}
}

View File

@@ -42,7 +42,7 @@ public final class Override5Kt$inlineMe$1$generic$2 {
inner class Override5Kt$inlineMe$1$generic$2
static method <clinit>(): void
public method <init>(): void
public synthetic bridge @org.jetbrains.annotations.Nullable method invoke(): java.lang.Object
public synthetic bridge method invoke(): java.lang.Object
public final method invoke(): void
}

View File

@@ -0,0 +1,11 @@
open class C<T> {
inner class A<U>(val x: T?, val y: U)
class D : C<Nothing>() {
fun f() = A<String>(null, "OK")
}
}
fun box(): String {
return C.D().f().y
}

View File

@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME

View File

@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME

View File

@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME

View File

@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
annotation class Ann
class Foo private @Ann constructor(@Ann s: String) {

View File

@@ -0,0 +1,22 @@
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Ann
@kotlin.Metadata
public final class Foo$Companion {
inner class Foo$Companion
private method <init>(): void
public synthetic method <init>(p0: kotlin.jvm.internal.DefaultConstructorMarker): void
public final method foo(): void
}
@kotlin.Metadata
public final class Foo {
public final static @org.jetbrains.annotations.NotNull field Companion: Foo$Companion
inner class Foo$Companion
static method <clinit>(): void
private @Ann method <init>(@Ann p0: java.lang.String): void
public synthetic method <init>(p0: java.lang.String, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic final static method access$foo(p0: Foo, p1: java.lang.String): void
private final @Ann method foo(@Ann p0: java.lang.String): void
}

View File

@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
annotation class Ann

View File

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

View File

@@ -10,13 +10,13 @@ synthetic final class Hello/Foo__MultifileSuspendKt$main$2 {
inner class Hello/Foo__MultifileSuspendKt$main$2
method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public synthetic bridge @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
@kotlin.jvm.JvmName
synthetic final class Hello/Foo__MultifileSuspendKt {
inner class Hello/Foo__MultifileSuspendKt$main$2
public synthetic final static method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public final static @org.jetbrains.annotations.Nullable method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[], @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
public synthetic final static method main(p0: java.lang.String[]): void
}

View File

@@ -1,5 +1,5 @@
@kotlin.Metadata
public final class ParameterlessMainKt {
public final static method main(): void
public synthetic final static method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public synthetic final static method main(p0: java.lang.String[]): void
}

View File

@@ -4,12 +4,12 @@ synthetic final class SuspendMainKt$main$2 {
inner class SuspendMainKt$main$2
method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public synthetic bridge @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
public final class SuspendMainKt {
inner class SuspendMainKt$main$2
public synthetic final static method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public final static @org.jetbrains.annotations.Nullable method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[], @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
public synthetic final static method main(p0: java.lang.String[]): void
}

View File

@@ -31,7 +31,7 @@ FILE fqName:<root> fileName:/ifElseIf.kt
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=true
WHEN type=kotlin.Any origin=IF
WHEN type=kotlin.Unit origin=IF
BRANCH
if: GET_VAR 'flag: kotlin.Boolean declared in <root>.testEmptyBranches1' type=kotlin.Boolean origin=null
then: CONST Boolean type=kotlin.Boolean value=true
@@ -45,7 +45,7 @@ FILE fqName:<root> fileName:/ifElseIf.kt
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=true
WHEN type=kotlin.Any origin=IF
WHEN type=kotlin.Unit origin=IF
BRANCH
if: GET_VAR 'flag: kotlin.Boolean declared in <root>.testEmptyBranches2' type=kotlin.Boolean origin=null
then: CONST Boolean type=kotlin.Boolean value=true

View File

@@ -140,6 +140,7 @@ public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
// 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) {

View File

@@ -140,7 +140,6 @@ public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
// 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) {

View File

@@ -16,8 +16,6 @@
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;
@@ -25,33 +23,20 @@ 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.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.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.openapi.vfs.*;
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.testFramework.fixtures.IdeaTestExecutionPolicy;
import com.intellij.util.*;
import com.intellij.util.Consumer;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
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.containers.hash.HashMap;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.ui.UIUtil;
import gnu.trove.Equality;
@@ -62,11 +47,11 @@ 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 org.junit.ComparisonFailure;
import java.io.File;
import java.io.FileNotFoundException;
@@ -76,19 +61,14 @@ import java.lang.reflect.Field;
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.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
/**
* @author peter
*/
@SuppressWarnings("ALL")
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public abstract class KtUsefulTestCase extends TestCase {
public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
public static final String TEMP_DIR_MARKER = "unitTest_";
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();
@@ -99,34 +79,24 @@ public abstract class KtUsefulTestCase extends TestCase {
private Application application;
static {
IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
//TODO: investigate and enable
//IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
Logger.setFactory(TestLoggerFactory.class);
}
protected static final Logger LOG = Logger.getInstance(KtUsefulTestCase.class);
@NotNull
private final Disposable myTestRootDisposable = new TestDisposable();
protected final Disposable myTestRootDisposable = new TestDisposable();
static Path ourPathToKeep;
private static final String ourPathToKeep = null;
private final List<String> myPathsToKeep = new ArrayList<>();
private String myTempDir;
private File 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;
@@ -135,42 +105,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// -- 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;
}
@@ -188,17 +122,11 @@ public abstract class KtUsefulTestCase extends TestCase {
super.setUp();
if (shouldContainTempFiles()) {
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
String testName = null;
if (policy != null) {
testName = policy.getPerTestTempDirName();
}
if (testName == null) {
testName = FileUtil.sanitizeFileName(getTestName(true));
}
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).getPath();
FileUtil.resetCanonicalTempPathCache(myTempDir);
myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
}
boolean isStressTest = isStressTest();
@@ -209,16 +137,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// 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
@@ -227,11 +145,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll(
() -> {
if (isIconRequired()) {
//IconManager.deactivate();
}
},
() -> disposeRootDisposable(),
() -> cleanupSwingDataStructures(),
() -> cleanupDeleteOnExitHookList(),
@@ -240,7 +153,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (shouldContainTempFiles()) {
FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
if (hasTmpFilesToKeep()) {
File[] files = new File(myTempDir).listFiles();
File[] files = myTempDir.listFiles();
if (files != null) {
for (File file : files) {
if (!shouldKeepTmpFile(file)) {
@@ -250,14 +163,15 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
else {
FileUtil.delete(new File(myTempDir));
FileUtil.delete(myTempDir);
}
}
},
() -> waitForAppLeakingThreads(10, TimeUnit.SECONDS)
).run(ObjectUtils.notNull(mySuppressedExceptions, Collections.emptyList()));
() -> UIUtil.removeLeakingAppleListeners()
).run();
}
finally {
super.tearDown();
// -- KOTLIN ADDITIONAL START --
TestApplicationUtilKt.resetApplicationToNull(application);
application = null;
@@ -274,12 +188,12 @@ public abstract class KtUsefulTestCase extends TestCase {
}
private boolean hasTmpFilesToKeep() {
return ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep.toString(), false) || !myPathsToKeep.isEmpty();
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.toString())) return true;
if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
for (String pathToKeep : myPathsToKeep) {
if (FileUtil.pathsEqual(path, pathToKeep)) return true;
}
@@ -287,7 +201,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 {
@@ -323,45 +237,12 @@ public abstract class KtUsefulTestCase extends TestCase {
@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;
@@ -371,11 +252,13 @@ public abstract class KtUsefulTestCase extends TestCase {
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);
@@ -398,6 +281,9 @@ public abstract class KtUsefulTestCase extends TestCase {
if (throwables[0] != null) {
throw throwables[0];
}
if (!completed.get()) {
throw new IllegalStateException("test didn't start");
}
}
protected boolean shouldRunTest() {
@@ -405,18 +291,19 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
if (runInDispatchThread()) {
//IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
//if (policy != null && !policy.runInDispatchThread()) {
// runnable.run();
//}
//else {
EdtTestUtilKt.runInEdtAndWait(() -> {
runnable.run();
return null;
});
}
else {
runnable.run();
}
//}
}
protected void defaultRunBare() throws Throwable {
private void defaultRunBare() throws Throwable {
Throwable exception = null;
try {
long setupStart = System.nanoTime();
@@ -437,17 +324,11 @@ public abstract class KtUsefulTestCase extends TestCase {
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;
}
/**
@@ -487,7 +368,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (runInDispatchThread()) {
TestRunnerUtil.replaceIdeEventQueueSafely();
EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
}
else {
defaultRunBare();
@@ -495,20 +376,13 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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()) {
@@ -641,20 +515,9 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> 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));
}
ArrayList<T> copy = new ArrayList<>(collection);
copy.retainAll(expected);
assertOrderedEquals(toString(collection), copy, expected);
}
@SafeVarargs
@@ -729,7 +592,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (collection.size() != checkers.length) {
Assert.fail(toString(collection));
}
Set<Consumer<T>> checkerSet = ContainerUtil.set(checkers);
Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
int i = 0;
Throwable lastError = null;
for (final T actual : collection) {
@@ -904,7 +767,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
System.out.println("File " + filePath + " created.");
}
fileText = FileUtil.loadFile(new File(filePath), StandardCharsets.UTF_8);
fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
}
catch (FileNotFoundException e) {
VfsTestUtil.overwriteTestData(filePath, actualText);
@@ -921,14 +784,14 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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.")) {
@@ -954,14 +817,6 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
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();
@@ -988,21 +843,6 @@ public abstract class KtUsefulTestCase extends TestCase {
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.
@@ -1016,42 +856,6 @@ public abstract class KtUsefulTestCase extends TestCase {
assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
}
/**
* 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.
*
@@ -1074,22 +878,21 @@ public abstract class KtUsefulTestCase extends TestCase {
private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
@NotNull AbstractExceptionCase<T> exceptionCase,
String expectedErrorMsgPart) throws T {
String expectedErrorMsg) throws T {
boolean wasThrown = false;
try {
exceptionCase.tryClosure();
}
catch (Throwable e) {
Throwable cause = e;
if (shouldOccur) {
wasThrown = true;
assertInstanceOf(cause, exceptionCase.getExpectedExceptionClass());
if (expectedErrorMsgPart != null) {
assertTrue(cause.getMessage(), cause.getMessage().contains(expectedErrorMsgPart));
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(cause.getClass())) {
else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
wasThrown = true;
//noinspection UseOfSystemOutOrSystemErr
@@ -1097,7 +900,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
e.printStackTrace(System.out);
fail("Exception isn't expected here. Exception message: " + cause.getMessage());
fail("Exception isn't expected here. Exception message: " + e.getMessage());
}
else {
throw e;
@@ -1105,7 +908,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
finally {
if (shouldOccur && !wasThrown) {
fail(exceptionCase.getExpectedExceptionClass().getName() + " must be thrown.");
fail(exceptionCase.getAssertionErrorMessage());
}
}
}
@@ -1134,7 +937,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static void refreshRecursively(@NotNull VirtualFile file) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
file.getChildren();
@@ -1144,27 +947,11 @@ public abstract class KtUsefulTestCase extends TestCase {
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;
@@ -1185,5 +972,5 @@ public abstract class KtUsefulTestCase extends TestCase {
String testName = getTestName(false);
return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
}
}
}
};
}

View File

@@ -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.ApplicationManager;
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.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 org.junit.ComparisonFailure;
import java.io.File;
import java.io.FileNotFoundException;
@@ -61,14 +76,19 @@ import java.lang.reflect.Field;
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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
// -- 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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
// 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 @@ public abstract class KtUsefulTestCase extends TestCase {
// 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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
@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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
if (throwables[0] != null) {
throw throwables[0];
}
if (!completed.get()) {
throw new IllegalStateException("test didn't start");
}
}
protected boolean shouldRunTest() {
@@ -291,19 +405,18 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
if (runInDispatchThread()) {
TestRunnerUtil.replaceIdeEventQueueSafely();
com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
}
else {
defaultRunBare();
@@ -376,13 +495,20 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
//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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
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.
@@ -856,6 +1016,42 @@ public abstract class KtUsefulTestCase extends TestCase {
assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
}
/**
* 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.
*
@@ -878,21 +1074,22 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
//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 @@ public abstract class KtUsefulTestCase extends TestCase {
}
finally {
if (shouldOccur && !wasThrown) {
fail(exceptionCase.getAssertionErrorMessage());
fail(exceptionCase.getExpectedExceptionClass().getName() + " must be thrown.");
}
}
}
@@ -937,7 +1134,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
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 @@ public abstract class KtUsefulTestCase extends TestCase {
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 @@ public abstract class KtUsefulTestCase extends TestCase {
String testName = getTestName(false);
return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
}
};
}
}
}

View File

@@ -15350,6 +15350,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/innerNested/innerGenericClassFromJava.kt");
}
@TestMetadata("innerImplicitParameter.kt")
public void testInnerImplicitParameter() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerImplicitParameter.kt");
}
@TestMetadata("innerJavaClass.kt")
public void testInnerJavaClass() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerJavaClass.kt");

View File

@@ -15350,6 +15350,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/innerNested/innerGenericClassFromJava.kt");
}
@TestMetadata("innerImplicitParameter.kt")
public void testInnerImplicitParameter() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerImplicitParameter.kt");
}
@TestMetadata("innerJavaClass.kt")
public void testInnerJavaClass() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerJavaClass.kt");

View File

@@ -14130,6 +14130,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/innerNested/innerGenericClassFromJava.kt");
}
@TestMetadata("innerImplicitParameter.kt")
public void testInnerImplicitParameter() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerImplicitParameter.kt");
}
@TestMetadata("innerJavaClass.kt")
public void testInnerJavaClass() throws Exception {
runTest("compiler/testData/codegen/box/innerNested/innerJavaClass.kt");

View File

@@ -1,18 +1,18 @@
versions.intellijSdk=202.5103-EAP-CANDIDATE-SNAPSHOT
versions.intellijSdk=193.6494.35
versions.androidBuildTools=r23.0.1
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.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.7.2
versions.jar.gson=2.8.6
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.7.1
versions.jar.lz4-java=1.6.0
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1
versions.shadow=5.2.0

View File

@@ -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

View File

@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.util
import com.intellij.DynamicBundle
import com.intellij.AbstractBundle
abstract class AbstractKotlinBundle protected constructor(pathToBundle: String) : DynamicBundle(pathToBundle) {
abstract class AbstractKotlinBundle protected constructor(pathToBundle: String) : AbstractBundle(pathToBundle) {
protected fun String.withHtml(): String = "<html>$this</html>"
}

View File

@@ -1,12 +0,0 @@
/*
* 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>"
}

View File

@@ -9,6 +9,6 @@ import com.intellij.psi.PsiMethod
import com.intellij.util.Processor
// FIX ME WHEN BUNCH 193 REMOVED
typealias StringProcessor = Processor<in String>
typealias PsiMethodProcessor = Processor<in PsiMethod>
typealias StringProcessor = Processor<String>
typealias PsiMethodProcessor = Processor<PsiMethod>

View File

@@ -1,14 +0,0 @@
/*
* 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>

View File

@@ -8,17 +8,13 @@ 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.AnnotationBuilder
import com.intellij.lang.annotation.Annotation
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(
@@ -32,67 +28,35 @@ class AnnotationPresentationInfo(
for (range in ranges) {
for (diagnostic in diagnostics) {
val fixes = fixesMap[diagnostic]
create(diagnostic, range, holder) { annotation ->
fixes.forEach {
when (it) {
is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix()
is IntentionAction -> annotation.newFix(it).registerFix()
}
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 (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.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix()
}
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, 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
}
private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation =
Diagnostic2Annotation.createAnnotation(
diagnostic,
range,
holder,
nonDefaultMessage,
textAttributes,
highlightType,
IdeErrorMessages::render
)
}

View File

@@ -1,62 +0,0 @@
/*
* 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
)
}

View File

@@ -64,7 +64,7 @@ public class ModuleHighlightUtil2 {
}
}
else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
return LightJavaModule.findModule(PsiManager.getInstance(project), root);
return LightJavaModule.getModule(PsiManager.getInstance(project), root);
}
}
else if ((root = index.getSourceRootForFile(file)) != null) {

View File

@@ -1,114 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.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;
}
}

View File

@@ -6,9 +6,12 @@
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.search.*
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
@@ -28,22 +31,19 @@ class KotlinReferenceScopeOptimizer : ScopeOptimizer {
val file = callable.parent as KtFile
val packageName = file.packageFqName.takeUnless { it.isRoot } ?: return null
val project = file.project
val searchHelper = PsiSearchHelper.getInstance(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
val kotlinFiles = mutableListOf<VirtualFile>()
searchHelper.processCandidateFilesForText(kotlinScope, UsageSearchContext.IN_CODE, true, packageName.asString()) {
kotlinFiles.add(it)
}
//TODO: use all components of package name?
val shortPackageName = packageName.shortName().identifier
val kotlinFiles = cacheManager.getVirtualFilesWithWord(shortPackageName, UsageSearchContext.IN_CODE, kotlinScope, true)
val javaFiles = mutableListOf<VirtualFile>()
searchHelper.processCandidateFilesForText(javaScope, UsageSearchContext.IN_CODE, true, file.javaFileFacadeFqName.asString()) {
javaFiles.add(it)
}
val javaFacadeName = file.javaFileFacadeFqName.shortName().identifier
val javaFiles = cacheManager.getVirtualFilesWithWord(javaFacadeName, UsageSearchContext.IN_CODE, javaScope, true)
return GlobalSearchScope.filesScope(project, kotlinFiles + javaFiles).uniteWith(restScope)
return GlobalSearchScope.filesScope(project, (kotlinFiles + javaFiles).asList()).uniteWith(restScope)
}
}

View File

@@ -1,49 +0,0 @@
/*
* 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)
}
}

View File

@@ -6,8 +6,8 @@ fun test() {
message("<caret>")
}
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "=1", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "=2", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "=3", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "=4", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "2", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysEmptyString" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysEmptyString" }
// NOTHING_ELSE

View File

@@ -6,8 +6,8 @@ fun test() {
message("<caret>foo")
}
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "=1", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "=2", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "=3", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "=4", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "bar.baz", itemText: "bar.baz", tailText: "2", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysNoPrefix" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysNoPrefix" }
// NOTHING_ELSE

View File

@@ -6,7 +6,7 @@ fun test() {
message("foo.<caret>")
}
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "=1", typeText: "PropertyKeysWithPrefix" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "=3", typeText: "PropertyKeysWithPrefix" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "=4", typeText: "PropertyKeysWithPrefix" }
// EXIST: { lookupString: "foo.bar", itemText: "foo.bar", tailText: "1", typeText: "PropertyKeysWithPrefix" }
// EXIST: { lookupString: "foo.bar.baz", itemText: "foo.bar.baz", tailText: "3", typeText: "PropertyKeysWithPrefix" }
// EXIST: { lookupString: "foo.test", itemText: "foo.test", tailText: "4", typeText: "PropertyKeysWithPrefix" }
// NOTHING_ELSE

View File

@@ -5,10 +5,9 @@
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() {
this.lookupFocusDegree = LookupFocusDegree.FOCUSED
focusDegree = LookupImpl.FocusDegree.FOCUSED
}

View File

@@ -1,13 +0,0 @@
/*
* 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
}

View File

@@ -1,27 +1,28 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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 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) : KotlinCodeBlockModificationListenerCompat(project) {
class KotlinCodeBlockModificationListener(
project: Project,
treeAspect: TreeAspect
) : KotlinCodeBlockModificationListenerCompat(project) {
init {
init(
TreeAspect.getInstance(project),
treeAspect,
incOCBCounter = { ktFile ->
kotlinOutOfCodeBlockTrackerImpl.incModificationCount()
perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true)
@@ -30,6 +31,7 @@ class KotlinCodeBlockModificationListener(project: Project) : KotlinCodeBlockMod
SimpleModificationTracker()
},
psiModificationTrackerListener = {
@Suppress("UnstableApiUsage")
val kotlinTrackerInternalIDECount =
modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount
if (kotlinModificationTracker == kotlinTrackerInternalIDECount) {
@@ -45,6 +47,7 @@ class KotlinCodeBlockModificationListener(project: Project) : KotlinCodeBlockMod
}
companion object {
fun getInstance(project: Project): KotlinCodeBlockModificationListener = project.getServiceSafe()
fun getInstance(project: Project): KotlinCodeBlockModificationListener =
project.getComponent(KotlinCodeBlockModificationListener::class.java)
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* 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)
}
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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
@@ -19,8 +8,8 @@ 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.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)
@@ -30,22 +19,22 @@ fun <T> runWriteAction(action: () -> T): T {
return ApplicationManager.getApplication().runWriteAction<T>(action)
}
fun Project.executeWriteCommand(name: String, command: () -> Unit) {
fun Project.executeWriteCommand(@Nls name: String, command: () -> Unit) {
CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
}
fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
fun <T> Project.executeWriteCommand(@Nls name: String, groupId: Any? = null, command: () -> T): T {
return executeCommand<T>(name, groupId) { runWriteAction(command) }
}
fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
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 = CancellationCheck.runWithCancellationCheck(block)
fun <T> runWithCancellationCheck(block: () -> T): T = block()
inline fun executeOnPooledThread(crossinline action: () -> Unit) =
ApplicationManager.getApplication().executeOnPooledThread { action() }

View File

@@ -1,48 +0,0 @@
/*
* 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}")

View File

@@ -45,7 +45,7 @@ class ShowKotlinGradleDslLogs : IntentionAction, AnAction(), DumbAware {
RevealFileAction.openDirectory(logsDir)
} else {
val parent = WindowManager.getInstance().getStatusBar(project)?.component
?: WindowManager.getInstance().findVisibleFrame()?.rootPane
?: WindowManager.getInstance().findVisibleFrame().rootPane
JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder(
KotlinIdeaGradleBundle.message(

View File

@@ -45,7 +45,7 @@ class ShowKotlinGradleDslLogs : IntentionAction, AnAction(), DumbAware {
RevealFileAction.openDirectory(logsDir)
} else {
val parent = WindowManager.getInstance().getStatusBar(project)?.component
?: WindowManager.getInstance().findVisibleFrame().rootPane
?: WindowManager.getInstance().findVisibleFrame()?.rootPane
JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder(
KotlinIdeaGradleBundle.message(

View File

@@ -13,8 +13,8 @@ import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExten
// 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)
}
}

View File

@@ -1,28 +0,0 @@
/*
* 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>,
)
}

View File

@@ -30,19 +30,21 @@ class KotlinGradleCoroutineDebugProjectResolver : AbstractProjectResolverExtensi
gradle.taskGraph.beforeTask { Task task ->
if (task instanceof Test) {
def kotlinxCoroutinesDebugJar = task.classpath.find { it.name.startsWith("kotlinx-coroutines-debug") }
if (kotlinxCoroutinesDebugJar)
task.jvmArgs ("-javaagent:${'$'}{kotlinxCoroutinesDebugJar?.absolutePath}", "-ea")
else {
for (lib in task.getClasspath()) {
def results = (lib.getName() =~ /kotlinx-coroutines-core\-([\d\.]+)\.jar${'$'}/).findAll()
if (results) {
def version = results.first()[1]
if (org.gradle.util.VersionNumber.parse( version ) >= org.gradle.util.VersionNumber.parse( '1.3.6' )) {
task.jvmArgs ("-javaagent:${'$'}{lib?.absolutePath}", "-ea")
}
def kotlinxCoroutinesCoreJar = task.classpath.find { it.name.startsWith("kotlinx-coroutines-core") }
if (kotlinxCoroutinesCoreJar) {
def results = (kotlinxCoroutinesCoreJar.getName() =~ /kotlinx-coroutines-core\-([\d\.]+)\.jar${'$'}/).findAll()
if (results) {
def version = results.first()[1]
if (org.gradle.util.VersionNumber.parse( version ) >= org.gradle.util.VersionNumber.parse('1.3.6')) {
task.jvmArgs ("-javaagent:${'$'}{kotlinxCoroutinesCoreJar?.absolutePath}", "-ea")
return
}
}
}
if (kotlinxCoroutinesDebugJar) {
task.jvmArgs ("-javaagent:${'$'}{kotlinxCoroutinesDebugJar?.absolutePath}", "-ea")
return
}
}
}
""".trimIndent()

View File

@@ -5,8 +5,7 @@
package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.openapi.externalSystem.autoimport.AsyncFileChangeListenerBase
import com.intellij.openapi.vfs.LocalFileSystem
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
@@ -18,27 +17,19 @@ fun addVfsListener(
) {
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) {
changedFiles.add(event.path)
watcher.fileChanged(event.path, file.timeStamp)
}
override fun apply() {
changedFiles.forEach {
LocalFileSystem.getInstance().findFileByPath(it)?.let { f ->
watcher.fileChanged(f.path, f.timeStamp)
}
}
}
// do nothing
override fun prepareFileDeletion(file: VirtualFile) {}
override fun apply() {}
override fun reset() {}
},
watcher.project
)

View File

@@ -1,36 +0,0 @@
/*
* 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
)
}

View File

@@ -7,100 +7,118 @@
package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.diff.util.DiffUtil
import com.intellij.notification.*
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
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.vfs.VirtualFile
import com.intellij.testFramework.LightVirtualFileBase
import org.jetbrains.kotlin.idea.KotlinFileType
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.registry.Registry
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.GradleBuildRootsManager
import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy
import org.jetbrains.kotlin.psi.UserDataProperty
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 runPartialGradleImport(project: Project) {
getGradleProjectSettings(project).forEach { gradleProjectSettings ->
getGradleProjectSettings(project).forEach {
ExternalSystemUtil.refreshProject(
gradleProjectSettings.externalProjectPath,
it.externalProjectPath,
ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
.projectResolverPolicy(
GradlePartialResolverPolicy { it is KotlinDslScriptModelResolver }
)
.build()
)
}
}
fun getMissingConfigurationNotificationText() = KotlinIdeaGradleBundle.message("script.configurations.will.be.available.after.load.changes")
fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.text.load.script.configurations")
fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.label.import.project")
fun autoReloadScriptConfigurations(project: Project): Boolean {
return GradleScriptDefinitionsContributor.getDefinitions(project).any {
KotlinScriptingSettings.getInstance(project).autoReloadConfigurations(it)
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectSettings = gradleSettings.getLinkedProjectsSettings()
.filterIsInstance<GradleProjectSettings>()
.firstOrNull()
if (projectSettings != null) {
return projectSettings.isUseAutoImport
}
return 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) {
if (!scriptConfigurationsNeedToBeUpdatedBalloon) return
if (autoReloadScriptConfigurations(project)) {
runPartialGradleImport(project)
} else {
// notification is shown in LoadConfigurationAction
// 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 = true
fun scriptConfigurationsAreUpToDate(project: Project): Boolean {
if (project.notificationPanel == null) return false
project.notificationPanel?.expire()
return 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
runPartialGradleImport(project)
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")) {
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectSettings = gradleSettings.getLinkedProjectsSettings()
.filterIsInstance<GradleProjectSettings>()
.firstOrNull()
if (projectSettings != null) {
projectSettings.isUseAutoImport = true
}
runPartialGradleImport(project)
})
}
override fun update(e: AnActionEvent) {
ensureValidActionVisibility(e)
override fun expire() {
super.expire()
project.notificationPanel = null
}
private fun ensureValidActionVisibility(e: AnActionEvent) {
val editor = e.getData(CommonDataKeys.EDITOR) ?: return
e.presentation.isVisible = getNotificationVisibility(editor)
}
private fun getNotificationVisibility(editor: Editor): Boolean {
if (DiffUtil.isDiffEditor(editor)) {
return false
private class LoadConfigurationAction : AnAction(KotlinIdeaGradleBundle.message("action.label.import.project")) {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
runPartialGradleImport(project)
}
val project = editor.project ?: return false
val file = getKotlinScriptFile(editor) ?: return false
if (autoReloadScriptConfigurations(project)) {
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)
}
}
}

View File

@@ -1,124 +0,0 @@
/*
* 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.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 org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
import org.jetbrains.kotlin.psi.UserDataProperty
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 runPartialGradleImport(project: Project) {
getGradleProjectSettings(project).forEach {
ExternalSystemUtil.refreshProject(
it.externalProjectPath,
ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
.build()
)
}
}
fun getMissingConfigurationActionText() = KotlinIdeaGradleBundle.message("action.label.import.project")
fun autoReloadScriptConfigurations(project: Project): Boolean {
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectSettings = gradleSettings.getLinkedProjectsSettings()
.filterIsInstance<GradleProjectSettings>()
.firstOrNull()
if (projectSettings != null) {
return projectSettings.isUseAutoImport
}
return 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) {
if (!scriptConfigurationsNeedToBeUpdatedBalloon) return
if (autoReloadScriptConfigurations(project)) {
// 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")) {
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectSettings = gradleSettings.getLinkedProjectsSettings()
.filterIsInstance<GradleProjectSettings>()
.firstOrNull()
if (projectSettings != null) {
projectSettings.isUseAutoImport = true
}
runPartialGradleImport(project)
})
}
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
runPartialGradleImport(project)
}
}
}

View File

@@ -10,7 +10,6 @@ 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
import kotlin.script.experimental.location.ScriptExpectedLocation
class GradleKotlinScriptDefinitionWrapper(
hostConfiguration: ScriptingHostConfiguration,
@@ -26,5 +25,6 @@ class GradleKotlinScriptDefinitionWrapper(
}
}
override val canAutoReloadScriptConfigurationsBeSwitchedOff = !kotlinDslScriptsModelImportSupported(gradleVersion)
override val canDefinitionBeSwitchedOff: Boolean = false
}

View File

@@ -1,30 +0,0 @@
/*
* 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
}

View File

@@ -5,16 +5,16 @@
package org.jetbrains.kotlin.idea.scripting.gradle.importing
import org.jetbrains.plugins.gradle.model.ClassSetImportModelProvider
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
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.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
import org.jetbrains.kotlin.idea.scripting.gradle.kotlinDslScriptsModelImportSupported
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
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
@@ -27,23 +27,27 @@ class KotlinDslScriptModelResolver : KotlinDslScriptModelResolverCommon() {
setOf(KotlinDslScriptAdditionalTask::class.java)
)
}
}
@Suppress("UnstableApiUsage")
class KotlinDslScriptModelContributor : ProjectModelContributor {
override fun accept(
projectModelBuilder: ModifiableGradleProjectModel,
toolingModelsProvider: ToolingModelsProvider,
resolverContext: ProjectResolverContext
override fun populateProjectExtraModels(gradleProject: IdeaProject, ideProject: DataNode<ProjectData>) {
super.populateProjectExtraModels(gradleProject, ideProject)
if (kotlinDslScriptsModelImportSupported(resolverCtx.projectGradleVersion)) {
populateBuildModels(resolverCtx.models.mainBuild, ideProject)
resolverCtx.models.includedBuilds.forEach { includedRoot ->
populateBuildModels(includedRoot, ideProject)
}
}
}
private fun populateBuildModels(
root: Build,
ideProject: DataNode<ProjectData>
) {
if (!kotlinDslScriptsModelImportSupported(resolverContext.projectGradleVersion)) return
toolingModelsProvider.projects().forEach {
val projectIdentifier = it.projectIdentifier.projectPath
if (projectIdentifier == ":") {
val model = toolingModelsProvider.getProjectModel(it, KotlinDslScriptsModel::class.java)
if (model != null) {
processScriptModel(resolverContext, model, projectIdentifier)
root.projects.forEach {
if (it.projectIdentifier.projectPath == ":") {
resolverCtx.models.getModel(it, KotlinDslScriptsModel::class.java)?.let { model ->
processScriptModel(resolverCtx, model, it.projectIdentifier.projectPath)
}
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.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)
if (kotlinDslScriptsModelImportSupported(resolverCtx.projectGradleVersion)) {
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 == ":") {
resolverCtx.models.getModel(it, KotlinDslScriptsModel::class.java)?.let { model ->
processScriptModel(resolverCtx, model, it.projectIdentifier.projectPath)
}
}
}
}
}

View File

@@ -147,8 +147,8 @@ public abstract class AbstractModelBuilderTest {
}
@NotNull
private static Set<Class<?>> getToolingExtensionClasses() {
Set<Class<?>> classes = ContainerUtil.set(
private static Set<Class> getToolingExtensionClasses() {
Set<Class> classes = ContainerUtil.<Class>set(
ExternalProject.class,
// gradle-tooling-extension-api jar
ProjectImportAction.class,
@@ -163,7 +163,7 @@ public abstract class AbstractModelBuilderTest {
}
@NotNull
private static Set<Class<?>> doGetToolingExtensionClasses() {
private static Set<Class> doGetToolingExtensionClasses() {
return Collections.emptySet();
}
@@ -174,7 +174,7 @@ public abstract class AbstractModelBuilderTest {
}
}
protected abstract Set<Class<?>> getModels();
protected abstract Set<Class> getModels();
private static void ensureTempDirCreated() throws IOException {

View File

@@ -1,233 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.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;
}
}
}

View File

@@ -23,7 +23,6 @@ import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import junit.framework.TestCase
import org.jetbrains.jps.model.java.JavaResourceRootType
@@ -731,12 +730,10 @@ class GradleFacetImportTest : GradleImportingTestCase() {
@Test
fun testJDKImport() {
val mockJdkPath = "compiler/testData/mockJDK"
object : WriteAction<Unit>() {
override fun run(result: Result<Unit>) {
val jdk = JavaSdk.getInstance().createJdk("myJDK", mockJdkPath)
val jdk = JavaSdk.getInstance().createJdk("myJDK", "my/path/to/jdk")
getProjectJdkTableSafe().addJdk(jdk)
ProjectRootManager.getInstance(myProject).projectSdk = jdk
}
}.execute()
@@ -747,13 +744,12 @@ class GradleFacetImportTest : GradleImportingTestCase() {
val moduleSDK = ModuleRootManager.getInstance(getModule("project_main")).sdk!!
Assert.assertTrue(moduleSDK.sdkType is JavaSdk)
Assert.assertEquals("myJDK", moduleSDK.name)
Assert.assertEquals(mockJdkPath, moduleSDK.homePath)
Assert.assertEquals("my/path/to/jdk", moduleSDK.homePath)
} finally {
object : WriteAction<Unit>() {
override fun run(result: Result<Unit>) {
val jdkTable = getProjectJdkTableSafe()
jdkTable.removeJdk(jdkTable.findJdk("myJDK")!!)
ProjectRootManager.getInstance(myProject).projectSdk = null
}
}.execute()
}

View File

@@ -32,7 +32,6 @@ import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.TestDialog
import com.intellij.openapi.util.io.FileUtil
@@ -140,7 +139,6 @@ abstract class GradleImportingTestCase : ExternalSystemImportingTestCase() {
TestCase.assertNotNull("Cannot create JDK for $myJdkHome", jdk)
if (!jdkTable.allJdks.contains(jdk)) {
jdkTable.addJdk(jdk!!, testRootDisposable)
ProjectRootManager.getInstance(myProject).projectSdk = jdk
}
FileTypeManager.getInstance().associateExtension(GroovyFileType.GROOVY_FILE_TYPE, "gradle")

View File

@@ -30,18 +30,15 @@ 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 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))
}
val contentManager = toolWindow.contentManager
val contentFactory = ContentFactory.SERVICE.getInstance()
contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, toolWindow), "", false))
}
toolWindow.activate(null)
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.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"
}
}

View File

@@ -20,12 +20,12 @@ 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.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 @@ private class ToolWindowScratchOutputHandler(private val parentDisposable: Dispo
OpenFileHyperlinkInfo(
project,
psiFile.virtualFile,
expression.lineStart
)
expression.lineStart,
),
)
print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
}
@@ -149,7 +149,7 @@ private class ToolWindowScratchOutputHandler(private val parentDisposable: Dispo
toolWindow.show(null)
}
toolWindow.setIcon(ExecutionUtil.getLiveIndicator(ScratchFileType.INSTANCE.icon))
toolWindow.icon = ExecutionUtil.getLiveIndicator(scratchIcon())
}
}
@@ -168,7 +168,7 @@ private class ToolWindowScratchOutputHandler(private val parentDisposable: Dispo
toolWindow.hide(null)
}
toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon is expected to be present"))
toolWindow.icon = scratchIcon()
}
}
@@ -187,18 +187,22 @@ private class ToolWindowScratchOutputHandler(private val parentDisposable: Dispo
val project = file.project
val toolWindowManager = ToolWindowManager.getInstance(project)
toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
val window =
toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID) ?: error("ScratchToolWindowFactory.ID should be registered")
val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
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}"
@@ -209,8 +213,8 @@ private class ScratchToolWindowFactory : ToolWindowFactory {
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val consoleView = ConsoleViewImpl(project, true)
toolWindow.setToHideOnEmptyContent(true)
toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon should be present"))
toolWindow.isToHideOnEmptyContent = true
toolWindow.icon = scratchIcon()
toolWindow.hide(null)
val contentManager = toolWindow.contentManager
@@ -238,27 +242,33 @@ private object TestOutputHandler : ScratchOutputHandlerAdapter() {
}
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>) {
@@ -266,7 +276,7 @@ private object TestOutputHandler : ScratchOutputHandlerAdapter() {
for (comment in comments) {
file.addAfter(
KtPsiFactory(file.project).createComment(comment),
file.lastChild
file.lastChild,
)
}
}

View File

@@ -1,284 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.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,
)
}
}
}
}

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