diff --git a/build.gradle.kts b/build.gradle.kts index b09b3bbe78a..35e4ede10de 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -357,7 +357,7 @@ fun Task.listConfigurationContents(configName: String) { } val defaultJvmTarget = "1.8" -val defaultJavaHome = jdkPath(defaultJvmTarget) +val defaultJavaHome = jdkPath(if (Platform[203].orHigher()) "11" else defaultJvmTarget) val ignoreTestFailures by extra(project.kotlinBuildProperties.ignoreTestFailures) allprojects { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt index 0da5b5de4ac..708a865de45 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt @@ -2,7 +2,7 @@ * 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. */ - +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package org.jetbrains.kotlin.codegen.inline.coroutines import com.intellij.util.ArrayUtil diff --git a/compiler/daemon/daemon-common-new/src/org/jetbrains/kotlin/daemon/common/experimental/socketInfrastructure/Client.kt b/compiler/daemon/daemon-common-new/src/org/jetbrains/kotlin/daemon/common/experimental/socketInfrastructure/Client.kt index 5c7ef93e28f..04d3f15854f 100644 --- a/compiler/daemon/daemon-common-new/src/org/jetbrains/kotlin/daemon/common/experimental/socketInfrastructure/Client.kt +++ b/compiler/daemon/daemon-common-new/src/org/jetbrains/kotlin/daemon/common/experimental/socketInfrastructure/Client.kt @@ -2,14 +2,16 @@ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ - +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure -import io.ktor.network.sockets.Socket -import kotlinx.coroutines.channels.* +import io.ktor.network.sockets.* import kotlinx.coroutines.* +import kotlinx.coroutines.channels.* import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface import org.jetbrains.kotlin.daemon.common.experimental.LoopbackNetworkInterfaceKtor +import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.AnyMessage +import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.ServerDownMessage import sun.net.ConnectionResetException import java.beans.Transient import java.io.IOException @@ -17,7 +19,6 @@ import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.io.Serializable import java.util.logging.Logger -import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.* interface Client : Serializable, AutoCloseable { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt index d6817d7932c..fd2b7ced0ec 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt @@ -44,7 +44,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.isInlineClassThatRequiresMangling import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType -import javax.rmi.CORBA.ClassDesc class LocalFunInlineChecker : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/elements/KtContractEffectElementType.kt.203 b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/elements/KtContractEffectElementType.kt.203 new file mode 100644 index 00000000000..cb9124601ae --- /dev/null +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/elements/KtContractEffectElementType.kt.203 @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi.stubs.elements + +import com.intellij.psi.PsiElement +import com.intellij.psi.stubs.StubElement +import com.intellij.psi.stubs.StubInputStream +import com.intellij.psi.stubs.StubOutputStream +import org.jetbrains.kotlin.psi.KtContractEffect +import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub +import org.jetbrains.kotlin.psi.stubs.impl.KotlinContractEffectStubImpl + +class KtContractEffectElementType(debugName: String, psiClass: Class) : + KtStubElementType(debugName, psiClass, KotlinContractEffectStub::class.java) { + override fun serialize(stub: KotlinContractEffectStub, dataStream: StubOutputStream) { + } + + override fun deserialize(dataStream: StubInputStream, parentStub: StubElement?): KotlinContractEffectStub { + return KotlinContractEffectStubImpl(parentStub, this) + } + + override fun createStub(psi: KtContractEffect, parentStub: StubElement<*>?): KotlinContractEffectStub { + return KotlinContractEffectStubImpl(parentStub, this) + } +} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt index 236d9fe38b9..98e622e390e 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/VMCounters.kt @@ -2,7 +2,7 @@ * 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("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.daemon.common.threadCpuTime diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinCompletionTestCase.java.203 b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinCompletionTestCase.java.203 index 98e99e4c987..2db3d1be91e 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinCompletionTestCase.java.203 +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KotlinCompletionTestCase.java.203 @@ -19,14 +19,13 @@ abstract public class KotlinCompletionTestCase extends CompletionTestCase { @Override protected void setUp() throws Exception { super.setUp(); - VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory()); + VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory()); CodeInsightSettings.getInstance().EXCLUDED_PACKAGES = new String[]{"excludedPackage", "somePackage.ExcludedClass"}; } @Override protected void tearDown() throws Exception { CodeInsightSettings.getInstance().EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY; - VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory()); super.tearDown(); } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.203 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.203 new file mode 100644 index 00000000000..a161f89e6bc --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.203 @@ -0,0 +1,82 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch.ui + +import com.intellij.core.JavaPsiBundle +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.Presentation +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.module.ModuleType +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.vcs.changes.committed.LabeledComboBoxAction +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.idea.KotlinJvmBundle +import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo +import org.jetbrains.kotlin.idea.caches.project.testSourceInfo +import org.jetbrains.kotlin.idea.scratch.ScratchFile +import org.jetbrains.kotlin.idea.scratch.isKotlinWorksheet +import java.util.function.Supplier +import javax.swing.JComponent + +class ModulesComboBoxAction(private val scratchFile: ScratchFile) : + LabeledComboBoxAction(KotlinJvmBundle.message("scratch.module.combobox")) +{ + override fun createPopupActionGroup(button: JComponent): DefaultActionGroup { + val actionGroup = DefaultActionGroup() + actionGroup.add(ModuleIsNotSelectedAction(JavaPsiBundle.messagePointer("list.item.no.module"))) + + val modules = ModuleManager.getInstance(scratchFile.project).modules.filter { + it.productionSourceInfo() != null || it.testSourceInfo() != null + } + + actionGroup.addAll(modules.map { SelectModuleAction(it) }) + + return actionGroup + } + + /** + * By default this action uses big font for label, so we have to decrease it + * to make it look the same as in [CheckboxAction]. + */ + override fun createCustomComponent(presentation: Presentation, place: String): JComponent { + val customComponent = super.createCustomComponent(presentation, place) + customComponent.components.forEach { it.font = UIUtil.getFont(UIUtil.FontSize.SMALL, it.font) } + return customComponent + } + + override fun update(e: AnActionEvent) { + super.update(e) + val selectedModule = scratchFile.module?.takeIf { !it.isDisposed } + + e.presentation.apply { + icon = selectedModule?.let { ModuleType.get(it).icon } + text = selectedModule?.name ?: JavaPsiBundle.message("list.item.no.module") + } + + e.presentation.isVisible = isModuleSelectorVisible() + } + + @TestOnly + fun isModuleSelectorVisible(): Boolean { + return !scratchFile.file.isKotlinWorksheet + } + + private inner class ModuleIsNotSelectedAction(placeholder: Supplier) : DumbAwareAction(placeholder) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(null) + } + } + + private inner class SelectModuleAction(private val module: Module) : + DumbAwareAction(module.name, null, ModuleType.get(module).icon) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(module) + } + } +} \ No newline at end of file diff --git a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java.203 b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java.203 new file mode 100644 index 00000000000..cd4e349bdcd --- /dev/null +++ b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java.203 @@ -0,0 +1,584 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven; + +import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TestDialog; +import com.intellij.openapi.util.AsyncResult; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.util.Consumer; +import com.intellij.util.PathUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.execution.MavenExecutor; +import org.jetbrains.idea.maven.execution.MavenRunnerParameters; +import org.jetbrains.idea.maven.execution.MavenRunnerSettings; +import org.jetbrains.idea.maven.execution.SoutMavenConsole; +import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; +import org.jetbrains.idea.maven.project.*; +import org.jetbrains.jps.model.java.JavaResourceRootType; +import org.jetbrains.jps.model.java.JavaSourceRootProperties; +import org.jetbrains.jps.model.java.JavaSourceRootType; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; +import org.jetbrains.kotlin.idea.test.KotlinSdkCreationChecker; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +@WithMutedInDatabaseRunTest +public abstract class MavenImportingTestCase extends MavenTestCase { + protected MavenProjectsTree myProjectsTree; + protected MavenProjectsManager myProjectsManager; + private File myGlobalSettingsFile; + protected KotlinSdkCreationChecker sdkCreationChecker; + + @Override + protected void setUp() throws Exception { + VfsRootAccess.allowRootAccess(getTestRootDisposable(), PathManager.getConfigPath()); + super.setUp(); + myGlobalSettingsFile = + MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().generalSettings.getEffectiveGlobalSettingsIoFile(); + if (myGlobalSettingsFile != null) { + VfsRootAccess.allowRootAccess(getTestRootDisposable(), myGlobalSettingsFile.getAbsolutePath()); + } + sdkCreationChecker = new KotlinSdkCreationChecker(); + } + + @Override + protected void setUpInWriteAction() throws Exception { + super.setUpInWriteAction(); + myProjectsManager = MavenProjectsManager.getInstance(myProject); + removeFromLocalRepository("test"); + } + + @Override + protected void tearDown() throws Exception { + try { + JavaAwareProjectJdkTableImpl.removeInternalJdkInTests(); + Messages.setTestDialog(TestDialog.DEFAULT); + removeFromLocalRepository("test"); + FileUtil.delete(BuildManager.getInstance().getBuildSystemDirectory().toFile()); + sdkCreationChecker.removeNewKotlinSdk(); + } + finally { + super.tearDown(); + } + } + + @Override + protected void runTest() throws Throwable { + KotlinTestUtils.runTestWithThrowable(this, () -> super.runTest()); + } + + protected void assertModules(String... expectedNames) { + Module[] actual = ModuleManager.getInstance(myProject).getModules(); + List actualNames = new ArrayList(); + + for (Module m : actual) { + actualNames.add(m.getName()); + } + + assertUnorderedElementsAreEqual(actualNames, expectedNames); + } + + protected void assertContentRoots(String moduleName, String... expectedRoots) { + List actual = new ArrayList(); + for (ContentEntry e : getContentRoots(moduleName)) { + actual.add(e.getUrl()); + } + + for (int i = 0; i < expectedRoots.length; i++) { + expectedRoots[i] = VfsUtil.pathToUrl(expectedRoots[i]); + } + + assertUnorderedPathsAreEqual(actual, Arrays.asList(expectedRoots)); + } + + protected void assertSources(String moduleName, String... expectedSources) { + assertContentFolders(moduleName, JavaSourceRootType.SOURCE, expectedSources); + } + + protected void assertGeneratedSources(String moduleName, String... expectedSources) { + ContentEntry contentRoot = getContentRoot(moduleName); + List folders = new ArrayList(); + for (SourceFolder folder : contentRoot.getSourceFolders(JavaSourceRootType.SOURCE)) { + JavaSourceRootProperties properties = folder.getJpsElement().getProperties(JavaSourceRootType.SOURCE); + assertNotNull(properties); + if (properties.isForGeneratedSources()) { + folders.add(folder); + } + } + doAssertContentFolders(contentRoot, folders, expectedSources); + } + + protected void assertResources(String moduleName, String... expectedSources) { + assertContentFolders(moduleName, JavaResourceRootType.RESOURCE, expectedSources); + } + + protected void assertTestSources(String moduleName, String... expectedSources) { + assertContentFolders(moduleName, JavaSourceRootType.TEST_SOURCE, expectedSources); + } + + protected void assertTestResources(String moduleName, String... expectedSources) { + assertContentFolders(moduleName, JavaResourceRootType.TEST_RESOURCE, expectedSources); + } + + protected void assertExcludes(String moduleName, String... expectedExcludes) { + ContentEntry contentRoot = getContentRoot(moduleName); + doAssertContentFolders(contentRoot, Arrays.asList(contentRoot.getExcludeFolders()), expectedExcludes); + } + + protected void assertContentRootExcludes(String moduleName, String contentRoot, String... expectedExcudes) { + ContentEntry root = getContentRoot(moduleName, contentRoot); + doAssertContentFolders(root, Arrays.asList(root.getExcludeFolders()), expectedExcudes); + } + + protected void assertContentFolders(String moduleName, @NotNull JpsModuleSourceRootType rootType, String... expected) { + ContentEntry contentRoot = getContentRoot(moduleName); + doAssertContentFolders(contentRoot, contentRoot.getSourceFolders(rootType), expected); + } + + private static void doAssertContentFolders(ContentEntry e, final List folders, String... expected) { + List actual = new ArrayList(); + for (ContentFolder f : folders) { + String rootUrl = e.getUrl(); + String folderUrl = f.getUrl(); + + if (folderUrl.startsWith(rootUrl)) { + int length = rootUrl.length() + 1; + folderUrl = folderUrl.substring(Math.min(length, folderUrl.length())); + } + + actual.add(folderUrl); + } + + assertOrderedElementsAreEqual(actual, Arrays.asList(expected)); + } + + protected void assertModuleOutput(String moduleName, String output, String testOutput) { + CompilerModuleExtension e = getCompilerExtension(moduleName); + + assertFalse(e.isCompilerOutputPathInherited()); + assertEquals(output, getAbsolutePath(e.getCompilerOutputUrl())); + assertEquals(testOutput, getAbsolutePath(e.getCompilerOutputUrlForTests())); + } + + private static String getAbsolutePath(String path) { + path = VfsUtil.urlToPath(path); + path = PathUtil.getCanonicalPath(path); + return FileUtil.toSystemIndependentName(path); + } + + protected void assertProjectOutput(String module) { + assertTrue(getCompilerExtension(module).isCompilerOutputPathInherited()); + } + + protected CompilerModuleExtension getCompilerExtension(String module) { + ModuleRootManager m = getRootManager(module); + return CompilerModuleExtension.getInstance(m.getModule()); + } + + protected void assertModuleLibDep(String moduleName, String depName) { + assertModuleLibDep(moduleName, depName, null); + } + + protected void assertModuleLibDep(String moduleName, String depName, String classesPath) { + assertModuleLibDep(moduleName, depName, classesPath, null, null); + } + + protected void assertModuleLibDep(String moduleName, String depName, String classesPath, String sourcePath, String javadocPath) { + LibraryOrderEntry lib = getModuleLibDep(moduleName, depName); + + assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath)); + assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath)); + assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), + javadocPath == null ? null : Collections.singletonList(javadocPath)); + } + + protected void assertModuleLibDep( + String moduleName, + String depName, + List classesPaths, + List sourcePaths, + List javadocPaths + ) { + LibraryOrderEntry lib = getModuleLibDep(moduleName, depName); + + assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths); + assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePaths); + assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPaths); + } + + private static void assertModuleLibDepPath(LibraryOrderEntry lib, OrderRootType type, List paths) { + if (paths == null) return; + assertUnorderedPathsAreEqual(Arrays.asList(lib.getRootUrls(type)), paths); + // also check the library because it may contain slight different set of urls (e.g. with duplicates) + assertUnorderedPathsAreEqual(Arrays.asList(lib.getLibrary().getUrls(type)), paths); + } + + protected void assertModuleLibDepScope(String moduleName, String depName, DependencyScope scope) { + LibraryOrderEntry dep = getModuleLibDep(moduleName, depName); + assertEquals(scope, dep.getScope()); + } + + private LibraryOrderEntry getModuleLibDep(String moduleName, String depName) { + return getModuleDep(moduleName, depName, LibraryOrderEntry.class); + } + + protected void assertModuleLibDeps(String moduleName, String... expectedDeps) { + assertModuleDeps(moduleName, LibraryOrderEntry.class, expectedDeps); + } + + protected void assertExportedDeps(String moduleName, String... expectedDeps) { + final List actual = new ArrayList(); + + getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly() + .process(new RootPolicy() { + @Override + public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) { + actual.add(e.getModuleName()); + return null; + } + + @Override + public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) { + actual.add(e.getLibraryName()); + return null; + } + }, null); + + assertOrderedElementsAreEqual(actual, expectedDeps); + } + + protected void assertModuleModuleDeps(String moduleName, String... expectedDeps) { + assertModuleDeps(moduleName, ModuleOrderEntry.class, expectedDeps); + } + + private void assertModuleDeps(String moduleName, Class clazz, String... expectedDeps) { + assertOrderedElementsAreEqual(collectModuleDepsNames(moduleName, clazz), expectedDeps); + } + + protected void assertModuleModuleDepScope(String moduleName, String depName, DependencyScope scope) { + ModuleOrderEntry dep = getModuleModuleDep(moduleName, depName); + assertEquals(scope, dep.getScope()); + } + + private ModuleOrderEntry getModuleModuleDep(String moduleName, String depName) { + return getModuleDep(moduleName, depName, ModuleOrderEntry.class); + } + + private List collectModuleDepsNames(String moduleName, Class clazz) { + List actual = new ArrayList(); + + for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) { + if (clazz.isInstance(e)) { + actual.add(e.getPresentableName()); + } + } + return actual; + } + + private T getModuleDep(String moduleName, String depName, Class clazz) { + T dep = null; + + for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) { + if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) { + dep = (T) e; + } + } + assertNotNull("Dependency not found: " + depName + + "\namong: " + collectModuleDepsNames(moduleName, clazz), + dep); + return dep; + } + + public void assertProjectLibraries(String... expectedNames) { + List actualNames = new ArrayList(); + for (Library each : ProjectLibraryTable.getInstance(myProject).getLibraries()) { + String name = each.getName(); + actualNames.add(name == null ? "" : name); + } + assertUnorderedElementsAreEqual(actualNames, expectedNames); + } + + protected void assertModuleGroupPath(String moduleName, String... expected) { + String[] path = ModuleManager.getInstance(myProject).getModuleGroupPath(getModule(moduleName)); + + if (expected.length == 0) { + assertNull(path); + } + else { + assertNotNull(path); + assertOrderedElementsAreEqual(Arrays.asList(path), expected); + } + } + + protected Module getModule(final String name) { + AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); + try { + Module m = ModuleManager.getInstance(myProject).findModuleByName(name); + assertNotNull("Module " + name + " not found", m); + return m; + } + finally { + accessToken.finish(); + } + } + + private ContentEntry getContentRoot(String moduleName) { + ContentEntry[] ee = getContentRoots(moduleName); + List roots = new ArrayList(); + for (ContentEntry e : ee) { + roots.add(e.getUrl()); + } + + String message = "Several content roots found: [" + StringUtil.join(roots, ", ") + "]"; + assertEquals(message, 1, ee.length); + + return ee[0]; + } + + private ContentEntry getContentRoot(String moduleName, String path) { + for (ContentEntry e : getContentRoots(moduleName)) { + if (e.getUrl().equals(VfsUtil.pathToUrl(path))) return e; + } + throw new AssertionError("content root not found"); + } + + public ContentEntry[] getContentRoots(String moduleName) { + return getRootManager(moduleName).getContentEntries(); + } + + private ModuleRootManager getRootManager(String module) { + return ModuleRootManager.getInstance(getModule(module)); + } + + protected void importProject(@NonNls String xml) throws IOException { + createProjectPom(xml); + importProject(); + } + + protected void importProject() { + importProjectWithProfiles(); + } + + protected void importProjectWithProfiles(String... profiles) { + doImportProjects(Collections.singletonList(myProjectPom), profiles); + } + + protected void importProjects(VirtualFile... files) { + doImportProjects(Arrays.asList(files)); + } + + private void doImportProjects(List files, String... profiles) { + initProjectsManager(false); + + readProjects(files, profiles); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.waitForResolvingCompletion(); + myProjectsManager.scheduleImportInTests(files); + myProjectsManager.importProjects(); + } + }); + + for (MavenProject each : myProjectsTree.getProjects()) { + if (each.hasReadingProblems()) { + System.out.println(each + " has problems: " + each.getProblems()); + } + } + } + + protected void readProjects(List files, String... profiles) { + myProjectsManager.resetManagedFilesAndProfilesInTests(files, new MavenExplicitProfiles(Arrays.asList(profiles))); + waitForReadingCompletion(); + } + + protected void updateProjectsAndImport(VirtualFile... files) { + readProjects(files); + myProjectsManager.performScheduledImportInTests(); + } + + protected void initProjectsManager(boolean enableEventHandling) { + myProjectsManager.initForTests(); + myProjectsTree = myProjectsManager.getProjectsTreeForTests(); + if (enableEventHandling) myProjectsManager.listenForExternalChanges(); + } + + protected void scheduleResolveAll() { + myProjectsManager.scheduleResolveAllInTests(); + } + + protected void waitForReadingCompletion() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + myProjectsManager.waitForReadingCompletion(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + protected void readProjects() { + readProjects(myProjectsManager.getProjectsFiles()); + } + + protected void readProjects(VirtualFile... files) { + List projects = new ArrayList(); + for (VirtualFile each : files) { + projects.add(myProjectsManager.findProject(each)); + } + myProjectsManager.forceUpdateProjects(projects); + waitForReadingCompletion(); + } + + protected void resolveDependenciesAndImport() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.waitForResolvingCompletion(); + myProjectsManager.performScheduledImportInTests(); + } + }); + } + + protected void resolveFoldersAndImport() { + myProjectsManager.scheduleFoldersResolveForAllProjects(); + myProjectsManager.waitForFoldersResolvingCompletion(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.performScheduledImportInTests(); + } + }); + } + + protected void resolvePlugins() { + myProjectsManager.waitForPluginsResolvingCompletion(); + } + + protected void downloadArtifacts() { + downloadArtifacts(myProjectsManager.getProjects(), null); + } + + protected MavenArtifactDownloader.DownloadResult downloadArtifacts( + Collection projects, + List artifacts + ) { + final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1]; + + AsyncResult result = new AsyncResult(); + result.doWhenDone(new Consumer() { + @Override + public void consume(MavenArtifactDownloader.DownloadResult unresolvedArtifacts) { + unresolved[0] = unresolvedArtifacts; + } + }); + + myProjectsManager.scheduleArtifactsDownloading(projects, artifacts, true, true, result); + myProjectsManager.waitForArtifactsDownloadingCompletion(); + + return unresolved[0]; + } + + protected void performPostImportTasks() { + myProjectsManager.waitForPostImportTasksCompletion(); + } + + protected void executeGoal(String relativePath, String goal) { + VirtualFile dir = myProjectRoot.findFileByRelativePath(relativePath); + + MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), Collections.emptyList()); + MavenRunnerSettings rs = new MavenRunnerSettings(); + MavenExecutor e = new MavenExternalExecutor(myProject, rp, getMavenGeneralSettings(), rs, new SoutMavenConsole()); + + e.execute(new EmptyProgressIndicator()); + } + + protected void removeFromLocalRepository(String relativePath) throws IOException { + FileUtil.delete(new File(getRepositoryPath(), relativePath)); + } + + protected void setupJdkForModules(String... moduleNames) { + for (String each : moduleNames) { + setupJdkForModule(each); + } + } + + protected Sdk setupJdkForModule(final String moduleName) { + final Sdk sdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk(); + ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk); + return sdk; + } + + protected static Sdk createJdk(String versionName) { + return IdeaTestUtil.getMockJdk17(versionName); + } + + protected static AtomicInteger configConfirmationForYesAnswer() { + final AtomicInteger counter = new AtomicInteger(); + Messages.setTestDialog(new TestDialog() { + @Override + public int show(String message) { + counter.set(counter.get() + 1); + return 0; + } + }); + return counter; + } + + protected static AtomicInteger configConfirmationForNoAnswer() { + final AtomicInteger counter = new AtomicInteger(); + Messages.setTestDialog(new TestDialog() { + @Override + public int show(String message) { + counter.set(counter.get() + 1); + return 1; + } + }); + return counter; + } +} diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java.203 b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java.203 index 652c418a3fc..4b7025d9d53 100644 --- a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java.203 +++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java.203 @@ -20,16 +20,10 @@ import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest; public abstract class KotlinCodeInsightTestCase extends CodeInsightTestCase { @Override protected void setUp() throws Exception { - VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory()); + VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory()); super.setUp(); } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory()); - } - @Override protected void runTestRunnable(@NotNull ThrowableRunnable testRunnable) throws Throwable { KotlinTestUtils.runTestWithThrowable(this, () -> super.runTestRunnable(testRunnable)); diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightPlatformCodeInsightFixtureTestCase.kt.203 b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightPlatformCodeInsightFixtureTestCase.kt.203 new file mode 100644 index 00000000000..558fc7cc4fd --- /dev/null +++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightPlatformCodeInsightFixtureTestCase.kt.203 @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.test + +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase +import com.intellij.util.ThrowableRunnable +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestMetadata +import java.io.File +import kotlin.reflect.full.findAnnotation + +abstract class KotlinLightPlatformCodeInsightFixtureTestCase : LightPlatformCodeInsightFixtureTestCase() { + protected open fun isFirPlugin(): Boolean = false + override fun setUp() { + super.setUp() + enableKotlinOfficialCodeStyle(project) + runPostStartupActivitiesOnce(project) + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) + if (!isFirPlugin()) { + invalidateLibraryCache(project) + } + } + + override fun tearDown() = runAll( + ThrowableRunnable { disableKotlinOfficialCodeStyle(project) }, + ThrowableRunnable { super.tearDown() }, + ) + + protected fun testDataFile(fileName: String): File = File(testDataPath, fileName) + + protected fun testDataFile(): File = testDataFile(fileName()) + + protected fun testPath(fileName: String = fileName()): String = testDataFile(fileName).toString() + + protected fun testPath(): String = testPath(fileName()) + + protected open fun fileName(): String = KotlinTestUtils.getTestDataFileName(this::class.java, this.name) ?: (getTestName(false) + ".kt") + + override fun getTestDataPath(): String = this::class.findAnnotation()?.value ?: super.getTestDataPath() +} diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt.203 b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt.203 new file mode 100644 index 00000000000..ac374e9b4e1 --- /dev/null +++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt.203 @@ -0,0 +1,76 @@ +/* + * 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.test + +import com.intellij.ide.highlighter.ModuleFileType +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileVisitor +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.PsiDocumentManager +import com.intellij.refactoring.MultiFileTestCase +import com.intellij.testFramework.PsiTestUtil +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.test.KotlinTestUtils + +abstract class KotlinMultiFileTestCase : MultiFileTestCase() { + protected var isMultiModule = false + + override fun setUp() { + super.setUp() + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) + + runWriteAction { + PluginTestCaseBase.addJdk(testRootDisposable, PluginTestCaseBase::mockJdk6) + ProjectRootManager.getInstance(project).projectSdk = PluginTestCaseBase.mockJdk6() + } + } + + protected fun getTestDirName(lowercaseFirstLetter: Boolean): String { + val testName = getTestName(lowercaseFirstLetter) + val endIndex = testName.lastIndexOf('_') + if (endIndex < 0) return testName + return testName.substring(0, endIndex).replace('_', '/') + } + + protected fun doTestCommittingDocuments(action: (VirtualFile, VirtualFile?) -> Unit) { + super.doTest( + { rootDir, rootAfter -> + action(rootDir, rootAfter) + + PsiDocumentManager.getInstance(project!!).commitAllDocuments() + FileDocumentManager.getInstance().saveAllDocuments() + }, getTestDirName(true) + ) + } + + override fun prepareProject(rootDir: VirtualFile) { + if (isMultiModule) { + val model = ModuleManager.getInstance(project).modifiableModel + + VfsUtilCore.visitChildrenRecursively( + rootDir, + object : VirtualFileVisitor() { + override fun visitFile(file: VirtualFile): Boolean { + if (!file.isDirectory && file.name.endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) { + model.loadModule(file.path) + return false + } + + return true + } + } + ) + + runWriteAction { model.commit() } + } else { + PsiTestUtil.addSourceContentToRoots(myModule, rootDir) + } + } +} \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt index bf87faddfd7..e7848231a7b 100644 --- a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt +++ b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading import com.sun.jdi.ArrayReference diff --git a/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt.203 b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt.203 new file mode 100644 index 00000000000..c0030ff88f5 --- /dev/null +++ b/idea/scripting-support/test/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt.203 @@ -0,0 +1,376 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch + +import com.intellij.ide.scratch.ScratchFileService +import com.intellij.ide.scratch.ScratchRootType +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.CompilerModuleExtension +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.testFramework.FileEditorManagerTestCase +import com.intellij.testFramework.MapDataContext +import com.intellij.testFramework.PsiTestUtil +import com.intellij.testFramework.TestActionEvent +import com.intellij.util.ui.UIUtil +import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil +import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction +import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction +import org.jetbrains.kotlin.idea.scratch.actions.ScratchCompilationSupport +import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer +import org.jetbrains.kotlin.idea.scratch.ui.KtScratchFileEditorWithPreview +import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.parsing.KotlinParserDefinition.Companion.STD_SCRIPT_SUFFIX +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.MockLibraryUtil +import org.jetbrains.kotlin.utils.PathUtil +import org.junit.Assert +import java.io.File + +abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { + + fun doRightPreviewPanelOutputTest(fileName: String) { + doRightPreviewPanelOutputTest(fileName = fileName, isRepl = false) + } + + fun doWorksheetReplTest(fileName: String) { + doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = true) + } + + fun doScratchReplTest(fileName: String) { + doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = false) + } + + fun doWorksheetCompilingTest(fileName: String) { + doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = true) + } + + fun doScratchCompilingTest(fileName: String) { + doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = false) + } + + fun doWorksheetMultiFileTest(dirName: String) { + doMultiFileTest(dirName, isWorksheet = true) + } + + fun doScratchMultiFileTest(dirName: String) { + doMultiFileTest(dirName, isWorksheet = false) + } + + private fun doMultiFileTest(dirName: String, isWorksheet: Boolean) { + val mainFileExtension = if (isWorksheet) KOTLIN_WORKSHEET_EXTENSION else STD_SCRIPT_SUFFIX + + val javaFiles = arrayListOf() + val kotlinFiles = arrayListOf() + val baseDir = File(testDataPath, dirName) + baseDir.walk().forEach { + if (it.isFile) { + if (it.extension == "java") javaFiles.add(it) + if (it.extension == "kt") kotlinFiles.add(it) + } + } + + val testDataPathFile = File(myFixture.testDataPath) + javaFiles.forEach { + myFixture.copyFileToProject( + FileUtil.getRelativePath(testDataPathFile, it)!!, + FileUtil.getRelativePath(baseDir, it)!! + ) + } + kotlinFiles.forEach { + myFixture.copyFileToProject( + FileUtil.getRelativePath(testDataPathFile, it)!!, + FileUtil.getRelativePath(baseDir, it)!! + ) + } + + val outputDir = FileUtil.createTempDirectory(dirName, "") + + if (javaFiles.isNotEmpty()) { + val options = listOf("-d", outputDir.path) + KotlinTestUtils.compileJavaFiles(javaFiles, options) + } + + MockLibraryUtil.compileKotlin(baseDir.path, outputDir) + + PsiTestUtil.setCompilerOutputPath(myFixture.module, outputDir.path, false) + + val mainFileName = "$dirName/${getTestName(true)}.$mainFileExtension" + doInlayOutputTest(mainFileName, isRepl = false, isWorksheet = isWorksheet) + + launchAction(ClearScratchAction()) + + doInlayOutputTest(mainFileName, isRepl = true, isWorksheet = isWorksheet) + + ModuleRootModificationUtil.updateModel(myFixture.module) { model -> + model.getModuleExtension(CompilerModuleExtension::class.java).inheritCompilerOutputPath(true) + } + } + + private fun doInlayOutputTest(fileName: String, isRepl: Boolean, isWorksheet: Boolean) { + configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = isWorksheet) + + val actualOutput = getFileTextWithInlays() + + val expectedFile = getExpectedFile(fileName, isRepl, suffix = "after") + KotlinTestUtils.assertEqualsToFile(expectedFile, actualOutput) + } + + private fun doRightPreviewPanelOutputTest(fileName: String, isRepl: Boolean) { + configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = false) + + val previewTextWithFoldings = getPreviewTextWithFoldings() + + val expectedFile = getExpectedFile(fileName, isRepl, suffix = "preview") + KotlinTestUtils.assertEqualsToFile(expectedFile, previewTextWithFoldings) + } + + private fun configureAndLaunchScratch(fileName: String, isRepl: Boolean, isWorksheet: Boolean) { + val sourceFile = File(testDataPath, fileName) + val fileText = sourceFile.readText().inlinePropertiesValues(isRepl) + + if (isWorksheet) { + configureWorksheetByText(sourceFile.name, fileText) + } else { + configureScratchByText(sourceFile.name, fileText) + } + + if (!KotlinHighlightingUtil.shouldHighlight(myFixture.file)) error("Highlighting for scratch file is switched off") + + launchScratch() + waitUntilScratchFinishes(isRepl) + } + + private fun getExpectedFile(fileName: String, isRepl: Boolean, suffix: String): File { + val expectedFileName = if (isRepl) { + fileName.replace(".kts", ".repl.$suffix") + } else { + fileName.replace(".kts", ".comp.$suffix") + } + + return File(testDataPath, expectedFileName) + } + + protected fun String.inlinePropertiesValues( + isRepl: Boolean = false, + isInteractiveMode: Boolean = false + ): String { + return replace("~REPL_MODE~", isRepl.toString()).replace("~INTERACTIVE_MODE~", isInteractiveMode.toString()) + } + + protected fun getFileTextWithInlays(): String { + val doc = myFixture.getDocument(myFixture.file) ?: error("Document for ${myFixture.file.name} is null") + val actualOutput = StringBuilder(myFixture.file.text) + for (line in doc.lineCount - 1 downTo 0) { + getInlays(doc.getLineStartOffset(line), doc.getLineEndOffset(line)) + .forEach { inlay -> + val str = inlay.toString() + val offset = doc.getLineEndOffset(line) + actualOutput.insert( + offset, + "${str.takeWhile { it.isWhitespace() }}// ${str.trim()}" + ) + } + } + return actualOutput.toString().trim() + } + + private fun getPreviewTextWithFoldings(): String { + val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile) + ?: error("Couldn't find scratch panel") + + val previewEditor = scratchFileEditor.getPreviewEditor() + return getFoldingData(previewEditor.editor, withCollapseStatus = false) + } + + protected fun getInlays(start: Int = 0, end: Int = myFixture.file.textLength): List { + val inlineElementsInRange = myFixture.editor.inlayModel + .getAfterLineEndElementsInRange(start, end) + .filter { it.renderer is InlayScratchFileRenderer } + return inlineElementsInRange.map { it.renderer as InlayScratchFileRenderer } + } + + protected fun configureScratchByText(name: String, text: String): ScratchFile { + val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile( + project, + name, + KotlinLanguage.INSTANCE, + text, + ScratchFileService.Option.create_if_missing + ) ?: error("Couldn't create scratch file") + + myFixture.openFileInEditor(scratchVirtualFile) + + ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file) + + val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile) + ?: error("Couldn't find scratch file") + + configureOptions(scratchFileEditor, text, myFixture.module) + + return scratchFileEditor.scratchFile + } + + protected fun configureWorksheetByText(name: String, text: String): ScratchFile { + val worksheetFile = myFixture.configureByText(name, text).virtualFile + + ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file) + + val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile) + ?: error("Couldn't find scratch panel") + + // We want to check that correct module is selected automatically, + // that's why we set `module` to null so it wouldn't be changed + configureOptions(scratchFileEditor, text, null) + + return scratchFileEditor.scratchFile + } + + + protected fun launchScratch() { + val action = RunScratchAction() + launchAction(action) + } + + protected fun launchAction(action: AnAction) { + val e = getActionEvent(myFixture.file.virtualFile, action) + action.beforeActionPerformedUpdate(e) + Assert.assertTrue(e.presentation.isEnabled && e.presentation.isVisible) + action.actionPerformed(e) + } + + protected fun waitUntilScratchFinishes(shouldStopRepl: Boolean = true) { + UIUtil.dispatchAllInvocationEvents() + + val start = System.currentTimeMillis() + // wait until output is displayed in editor or for 1 minute + while (ScratchCompilationSupport.isAnyInProgress()) { + if ((System.currentTimeMillis() - start) > TIME_OUT) { + LOG.warn("Waiting timeout $TIME_OUT ms is exceed") + break + } + Thread.sleep(100) + } + + if (shouldStopRepl) stopReplProcess() + + UIUtil.dispatchAllInvocationEvents() + } + + protected fun stopReplProcess() { + if (myFixture.file != null) { + val scratchFile = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)?.scratchFile + ?: error("Couldn't find scratch panel") + scratchFile.replScratchExecutor?.stopAndWait() + } + + UIUtil.dispatchAllInvocationEvents() + } + + private fun getActionEvent(virtualFile: VirtualFile, action: AnAction): TestActionEvent { + val context = MapDataContext() + context.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, arrayOf(virtualFile)) + context.put(CommonDataKeys.PROJECT, project) + context.put(CommonDataKeys.EDITOR, myFixture.editor) + return TestActionEvent(context, action) + } + + protected fun testScratchText(): String { + return File(testDataPath, "idea/scripting-support/testData/scratch/custom/test_scratch.kts").readText() + } + + override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory() + + + override fun getProjectDescriptor(): com.intellij.testFramework.LightProjectDescriptor { + val testName = getTestName(false) + + return when { + testName.endsWith("WithKotlinTest") -> INSTANCE_WITH_KOTLIN_TEST + testName.endsWith("NoRuntime") -> INSTANCE_WITHOUT_RUNTIME + testName.endsWith("ScriptRuntime") -> INSTANCE_WITH_SCRIPT_RUNTIME + else -> KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK + } + } + + override fun setUp() { + super.setUp() + + VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory()) + + PluginTestCaseBase.addJdk(myFixture.projectDisposable) { PluginTestCaseBase.fullJdk() } + } + + override fun tearDown() { + super.tearDown() + + ScratchFileService.getInstance().scratchesMapping.mappings.forEach { file, _ -> + runWriteAction { file.delete(this) } + } + } + + companion object { + private const val TIME_OUT = 60000 // 1 min + + private val INSTANCE_WITH_KOTLIN_TEST = object : KotlinWithJdkAndRuntimeLightProjectDescriptor( + arrayListOf( + ForTestCompileRuntime.runtimeJarForTests(), + PathUtil.kotlinPathsForDistDirectory.kotlinTestPath + ) + ) { + override fun getSdk() = PluginTestCaseBase.fullJdk() + } + + private val INSTANCE_WITHOUT_RUNTIME = object : KotlinLightProjectDescriptor() { + override fun getSdk() = PluginTestCaseBase.fullJdk() + } + + private val INSTANCE_WITH_SCRIPT_RUNTIME = object : KotlinWithJdkAndRuntimeLightProjectDescriptor( + arrayListOf( + ForTestCompileRuntime.runtimeJarForTests(), + ForTestCompileRuntime.scriptRuntimeJarForTests() + ) + ) { + override fun getSdk() = PluginTestCaseBase.fullJdk() + } + + fun configureOptions( + scratchFileEditor: KtScratchFileEditorWithPreview, + fileText: String, + module: Module? + ) { + val scratchFile = scratchFileEditor.scratchFile + + if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// INTERACTIVE_MODE: ") != true) { + scratchFile.saveOptions { copy(isInteractiveMode = false) } + } + + if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// REPL_MODE: ") == true) { + scratchFile.saveOptions { copy(isRepl = true) } + } + + if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) { + scratchFile.setModule(module) + } + + val isPreviewEnabled = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// PREVIEW_ENABLED: ") == true + scratchFileEditor.setPreviewEnabled(isPreviewEnabled) + } + + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.203 b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.203 new file mode 100644 index 00000000000..e9504f41ff6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProviderCompat.kt.203 @@ -0,0 +1,39 @@ +/* + * 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 + +import com.intellij.codeInsight.javadoc.JavaDocExternalFilter +import com.intellij.psi.PsiDocCommentBase +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import java.util.function.Consumer + +// FIX ME WHEN BUNCH 201 REMOVED +class KotlinDocumentationProvider : KotlinDocumentationProviderCompatBase() { + + override fun collectDocComments(file: PsiFile, sink: Consumer) { + if (file !is KtFile) return + + PsiTreeUtil.processElements(file) { + val comment = (it as? KtDeclaration)?.docComment + if (comment != null) sink.accept(comment) + true + } + } + + override fun generateRenderedDoc(element: PsiElement): String? { + val docComment = (element as? KtDeclaration)?.docComment ?: return null + + val result = StringBuilder().also { + it.renderKDoc(docComment.getDefaultSection(), docComment.getAllSections()) + } + + return JavaDocExternalFilter.filterInternalDocInfo(result.toString()) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/framework/KotlinSdkType.kt.203 b/idea/src/org/jetbrains/kotlin/idea/framework/KotlinSdkType.kt.203 new file mode 100644 index 00000000000..227122e3d1e --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/framework/KotlinSdkType.kt.203 @@ -0,0 +1,90 @@ +/* + * Copyright 2000-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.framework + +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.projectRoots.* +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil +import com.intellij.util.Consumer +import org.jdom.Element +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.KotlinIcons +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion +import org.jetbrains.kotlin.utils.PathUtil +import javax.swing.JComponent + +class KotlinSdkType : SdkType("KotlinSDK") { + companion object { + @JvmField + val INSTANCE = KotlinSdkType() + + val defaultHomePath: String + get() = PathUtil.kotlinPathsForIdeaPlugin.homePath.absolutePath + + @JvmOverloads + fun setUpIfNeeded(disposable: Disposable? = null, checkIfNeeded: () -> Boolean = { true }) { + val projectSdks: Array = ProjectJdkTable.getInstance().allJdks + if (projectSdks.any { it.sdkType is KotlinSdkType }) return + if (!checkIfNeeded()) return // do not create Kotlin SDK + + val newSdkName = SdkConfigurationUtil.createUniqueSdkName(INSTANCE, defaultHomePath, projectSdks.toList()) + val newJdk = ProjectJdkImpl(newSdkName, INSTANCE) + newJdk.homePath = defaultHomePath + INSTANCE.setupSdkPaths(newJdk) + + ApplicationManager.getApplication().invokeAndWait { + runWriteAction { + if (ProjectJdkTable.getInstance().allJdks.any { it.sdkType is KotlinSdkType }) return@runWriteAction + if (disposable != null) { + ProjectJdkTable.getInstance().addJdk(newJdk, disposable) + } else { + ProjectJdkTable.getInstance().addJdk(newJdk) + } + } + } + } + } + + override fun getPresentableName() = KotlinBundle.message("framework.name.kotlin.sdk") + + override fun getIcon() = KotlinIcons.SMALL_LOGO + + override fun isValidSdkHome(path: String?) = true + + override fun suggestSdkName(currentSdkName: String?, sdkHome: String?) = "Kotlin SDK" + + override fun suggestHomePath() = null + + override fun sdkHasValidPath(sdk: Sdk) = true + + override fun getVersionString(sdk: Sdk) = bundledRuntimeVersion() + + override fun supportsCustomCreateUI() = true + + override fun showCustomCreateUI(sdkModel: SdkModel, parentComponent: JComponent, selectedSdk: Sdk?, sdkCreatedCallback: Consumer) { + sdkCreatedCallback.consume(createSdkWithUniqueName(sdkModel.sdks.toList())) + } + + fun createSdkWithUniqueName(existingSdks: Collection): ProjectJdkImpl { + val sdkName = suggestSdkName(SdkConfigurationUtil.createUniqueSdkName(this, "", existingSdks), "") + return ProjectJdkImpl(sdkName, this).apply { + homePath = defaultHomePath + } + } + + override fun createAdditionalDataConfigurable(sdkModel: SdkModel, sdkModificator: SdkModificator) = null + + override fun saveAdditionalData(additionalData: SdkAdditionalData, additional: Element) { + + } + + override fun allowCreationByUser(): Boolean { + return false + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/reporter/ITNReporterCompat.kt.203 b/idea/src/org/jetbrains/kotlin/idea/reporter/ITNReporterCompat.kt.203 new file mode 100644 index 00000000000..3283c8d4d2b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/reporter/ITNReporterCompat.kt.203 @@ -0,0 +1,33 @@ +/* + * 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.reporter + +import com.intellij.diagnostic.ITNReporter +import com.intellij.openapi.diagnostic.IdeaLoggingEvent +import com.intellij.openapi.diagnostic.SubmittedReportInfo +import com.intellij.util.Consumer +import java.awt.Component + +abstract class ITNReporterCompat : ITNReporter() { + final override fun submit( + events: Array, + additionalInfo: String?, + parentComponent: Component, + consumer: Consumer + ): Boolean { + return submitCompat(events, additionalInfo, parentComponent, consumer) + } + + open fun submitCompat( + events: Array, + additionalInfo: String?, + parentComponent: Component?, + consumer: Consumer + ): Boolean { + @Suppress("IncompatibleAPI") + return super.submit(events, additionalInfo, parentComponent ?: error("Should never happen in Intellij Idea"), consumer) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/reporter/KotlinReportSubmitter.kt.203 b/idea/src/org/jetbrains/kotlin/idea/reporter/KotlinReportSubmitter.kt.203 new file mode 100644 index 00000000000..836ff2b4cb5 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/reporter/KotlinReportSubmitter.kt.203 @@ -0,0 +1,298 @@ +/* + * 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.reporter + +import com.intellij.diagnostic.ReportMessages +import com.intellij.ide.DataManager +import com.intellij.ide.util.PropertiesComponent +import com.intellij.notification.NotificationType +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.IdeaLoggingEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.diagnostic.SubmittedReportInfo +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.util.Consumer +import com.intellij.util.ThreeState +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.KotlinPluginUpdater +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.PluginUpdateStatus +import org.jetbrains.kotlin.idea.util.isEap +import java.awt.Component +import java.io.IOException +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException +import java.time.temporal.ChronoUnit +import javax.swing.Icon + +/** + * We need to wrap ITNReporter for force showing or errors from kotlin plugin even from released version of IDEA. + */ +class KotlinReportSubmitter : ITNReporterCompat() { + companion object { + private const val KOTLIN_FATAL_ERROR_NOTIFICATION_PROPERTY = "kotlin.fatal.error.notification" + private const val IDEA_FATAL_ERROR_NOTIFICATION_PROPERTY = "idea.fatal.error.notification" + private const val DISABLED_VALUE = "disabled" + private const val ENABLED_VALUE = "enabled" + + private const val KOTLIN_PLUGIN_RELEASE_DATE = "kotlin.plugin.releaseDate" + + private val LOG = Logger.getInstance(KotlinReportSubmitter::class.java) + + @Volatile + private var isFatalErrorReportingDisabledInRelease = ThreeState.UNSURE + + private val isIdeaAndKotlinRelease by lazy { + // Disabled in released version of IDEA and Android Studio + // Enabled in EAPs, Canary and Beta + val isReleaseLikeIdea = DISABLED_VALUE == System.getProperty(IDEA_FATAL_ERROR_NOTIFICATION_PROPERTY, ENABLED_VALUE) + + val isKotlinRelease = + !(KotlinPluginUtil.isSnapshotVersion() || KotlinPluginUtil.isDevVersion() || isEap(KotlinPluginUtil.getPluginVersion())) + + isReleaseLikeIdea && isKotlinRelease + } + + private const val NUMBER_OF_REPORTING_DAYS_FROM_RELEASE = 7 + + fun setupReportingFromRelease() { + if (ApplicationManager.getApplication().isUnitTestMode) { + return + } + + if (!isIdeaAndKotlinRelease) { + return + } + + val currentPluginReleaseDate = readStoredPluginReleaseDate() + if (currentPluginReleaseDate != null) { + isFatalErrorReportingDisabledInRelease = + if (isFatalErrorReportingDisabled(currentPluginReleaseDate)) ThreeState.YES else ThreeState.NO + return + } + + ApplicationManager.getApplication().executeOnPooledThread { + val releaseDate = + try { + KotlinPluginUpdater.fetchPluginReleaseDate( + KotlinPluginUtil.KOTLIN_PLUGIN_ID, + KotlinPluginUtil.getPluginVersion(), + null + ) + } catch (e: IOException) { + LOG.warn(e) + null + } catch (e: KotlinPluginUpdater.Companion.ResponseParseException) { + // Exception won't be shown, but will be logged + LOG.error(e) + return@executeOnPooledThread + } + + if (releaseDate != null) { + writePluginReleaseValue(releaseDate) + } else { + // Will try to fetch the same release date on IDE restart + } + + isFatalErrorReportingDisabledInRelease = isFatalErrorReportingWithDefault(releaseDate) + } + } + + private fun isFatalErrorReportingWithDefault(releaseDate: LocalDate?): ThreeState { + return if (releaseDate != null) { + if (isFatalErrorReportingDisabled(releaseDate)) ThreeState.YES else ThreeState.NO + } else { + // Disable reporting by default until we obtain a valid release date. + // We might fail reporting exceptions that happened before initialization but after successful release date fetching + // such exceptions maybe be reported after restart. + ThreeState.YES + } + } + + private fun isFatalErrorReportingDisabledWithUpdate(): Boolean { + val currentPluginReleaseDate = readStoredPluginReleaseDate() + isFatalErrorReportingDisabledInRelease = isFatalErrorReportingWithDefault(currentPluginReleaseDate) + + return isFatalErrorReportingDisabledInRelease == ThreeState.YES + } + + private fun isFatalErrorReportingDisabled(releaseDate: LocalDate): Boolean { + return ChronoUnit.DAYS.between(releaseDate, LocalDate.now()) > NUMBER_OF_REPORTING_DAYS_FROM_RELEASE + } + + private val RELEASE_DATE_FORMATTER: DateTimeFormatter by lazy { + DateTimeFormatter.ofPattern("yyyy-MM-dd") + } + + private fun readStoredPluginReleaseDate(): LocalDate? { + val pluginVersionToReleaseDate = PropertiesComponent.getInstance().getValue(KOTLIN_PLUGIN_RELEASE_DATE) ?: return null + + val parsedDate = fun(): LocalDate? { + val parts = pluginVersionToReleaseDate.split(":") + if (parts.size != 2) { + return null + } + + val pluginVersion = parts[0] + if (pluginVersion != KotlinPluginUtil.getPluginVersion()) { + // Stored for some other plugin version + return null + } + + return try { + val dateString = parts[1] + LocalDate.parse(dateString, RELEASE_DATE_FORMATTER) + } catch (e: DateTimeParseException) { + null + } + }.invoke() + + if (parsedDate == null) { + PropertiesComponent.getInstance().setValue(KOTLIN_PLUGIN_RELEASE_DATE, null) + } + + return parsedDate + } + + private fun writePluginReleaseValue(date: LocalDate) { + val currentKotlinVersion = KotlinPluginUtil.getPluginVersion() + val dateStr = RELEASE_DATE_FORMATTER.format(date) + PropertiesComponent.getInstance().setValue(KOTLIN_PLUGIN_RELEASE_DATE, "$currentKotlinVersion:$dateStr") + } + } + + private var hasUpdate = false + private var hasLatestVersion = false + + override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean { + if (ApplicationManager.getApplication().isInternal) { + // Reporting is always enabled for internal mode in the platform + return true + } + + if (ApplicationManager.getApplication().isUnitTestMode) { + return true + } + + if (hasUpdate) { + return false + } + + val kotlinNotificationEnabled = DISABLED_VALUE != System.getProperty(KOTLIN_FATAL_ERROR_NOTIFICATION_PROPERTY, ENABLED_VALUE) + if (!kotlinNotificationEnabled) { + // Kotlin notifications are explicitly disabled + return false + } + + if (!isIdeaAndKotlinRelease) { + return true + } + + return when (isFatalErrorReportingDisabledInRelease) { + ThreeState.YES -> + false + + ThreeState.NO -> { + // Reiterate the check for the case when there was no restart for long and reporting decision might expire + !isFatalErrorReportingDisabledWithUpdate() + } + + ThreeState.UNSURE -> { + // There might be an exception while initialization isn't complete. + // Decide urgently based on previously stored release version if already fetched. + !isFatalErrorReportingDisabledWithUpdate() + } + } + } + + override fun submitCompat( + events: Array, + additionalInfo: String?, + parentComponent: Component?, + consumer: Consumer + ): Boolean { + if (hasUpdate) { + if (ApplicationManager.getApplication().isInternal) { + return super.submitCompat(events, additionalInfo, parentComponent, consumer) + } + + // TODO: What happens here? User clicks report but no report is send? + return true + } + + if (hasLatestVersion) { + return super.submitCompat(events, additionalInfo, parentComponent, consumer) + } + + val project: Project? = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent)) + if (KotlinPluginUtil.isPatched()) { + ReportMessages.GROUP + .createNotification( + ReportMessages.ERROR_REPORT, + KotlinBundle.message("reporter.text.can.t.report.exception.from.patched.plugin"), + NotificationType.INFORMATION, + null + ) + .setImportant(false) + .notify(project) + return true + } + + KotlinPluginUpdater.getInstance().runUpdateCheck { status -> + if (status is PluginUpdateStatus.Update) { + hasUpdate = true + + if (ApplicationManager.getApplication().isInternal) { + super.submitCompat(events, additionalInfo, parentComponent, consumer) + } + + val rc = showDialog( + parentComponent, + KotlinBundle.message( + "reporter.message.text.you.re.running.kotlin.plugin.version", + KotlinPluginUtil.getPluginVersion(), + status.pluginDescriptor.version + ), + KotlinBundle.message("reporter.title.update.kotlin.plugin"), + arrayOf(KotlinBundle.message("reporter.button.text.update"), KotlinBundle.message("reporter.button.text.ignore")), + 0, Messages.getInformationIcon() + ) + + if (rc == 0) { + KotlinPluginUpdater.getInstance().installPluginUpdate(status) + } + } else { + hasLatestVersion = true + super.submitCompat(events, additionalInfo, parentComponent, consumer) + } + false + } + + return true + } + + fun showDialog(parent: Component?, message: String, title: String, options: Array, defaultOptionIndex: Int, icon: Icon?): Int { + return if (parent != null) { + Messages.showDialog(parent, message, title, options, defaultOptionIndex, icon) + } else { + Messages.showDialog(message, title, options, defaultOptionIndex, icon) + } + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java.203 b/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java.203 new file mode 100644 index 00000000000..029612bac65 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/KotlinDaemonAnalyzerTestCase.java.203 @@ -0,0 +1,18 @@ +/* + * 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; + +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; +import org.jetbrains.kotlin.test.KotlinTestUtils; + +abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase { + @Override + protected void setUp() throws Exception { + VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory()); + super.setUp(); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt.203 b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt.203 new file mode 100644 index 00000000000..0425a029acc --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt.203 @@ -0,0 +1,488 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.resolve + +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.StdModuleTypes +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.roots.impl.libraries.LibraryEx +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.PsiManager +import com.intellij.testFramework.ModuleTestCase +import com.intellij.testFramework.PsiTestUtil +import com.intellij.testFramework.UsefulTestCase +import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime +import org.jetbrains.kotlin.idea.caches.project.* +import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo +import org.jetbrains.kotlin.idea.caches.project.ModuleTestSourceInfo +import org.jetbrains.kotlin.idea.framework.CommonLibraryKind +import org.jetbrains.kotlin.idea.framework.JSLibraryKind +import org.jetbrains.kotlin.idea.framework.platform +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.* +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.util.addDependency +import org.jetbrains.kotlin.test.util.jarRoot +import org.jetbrains.kotlin.test.util.projectLibrary +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.junit.Assert +import org.junit.runner.RunWith + +@RunWith(JUnit3WithIdeaConfigurationRunner::class) +class IdeaModuleInfoTest : ModuleTestCase() { + fun testSimpleModuleDependency() { + val (a, b) = modules() + b.addDependency(a) + + b.production.assertDependenciesEqual(b.production, a.production) + UsefulTestCase.assertDoesntContain(a.production.dependencies(), b.production) + } + + fun testCircularDependency() { + val (a, b) = modules() + + b.addDependency(a) + a.addDependency(b) + + a.production.assertDependenciesEqual(a.production, b.production) + b.production.assertDependenciesEqual(b.production, a.production) + } + + fun testExportedDependency() { + val (a, b, c) = modules() + + b.addDependency(a, exported = true) + c.addDependency(b) + + a.production.assertDependenciesEqual(a.production) + b.production.assertDependenciesEqual(b.production, a.production) + c.production.assertDependenciesEqual(c.production, b.production, a.production) + } + + fun testRedundantExportedDependency() { + val (a, b, c) = modules() + + b.addDependency(a, exported = true) + c.addDependency(a) + c.addDependency(b) + + a.production.assertDependenciesEqual(a.production) + b.production.assertDependenciesEqual(b.production, a.production) + c.production.assertDependenciesEqual(c.production, a.production, b.production) + } + + fun testCircularExportedDependency() { + val (a, b, c) = modules() + + b.addDependency(a, exported = true) + c.addDependency(b, exported = true) + a.addDependency(c, exported = true) + + a.production.assertDependenciesEqual(a.production, c.production, b.production) + b.production.assertDependenciesEqual(b.production, a.production, c.production) + c.production.assertDependenciesEqual(c.production, b.production, a.production) + } + + fun testSimpleLibDependency() { + val a = module("a") + val lib = projectLibrary() + a.addDependency(lib) + + a.production.assertDependenciesEqual(a.production, lib.classes) + } + + fun testCircularExportedDependencyWithLib() { + val (a, b, c) = modules() + + val lib = projectLibrary() + + a.addDependency(lib) + + b.addDependency(a, exported = true) + c.addDependency(b, exported = true) + a.addDependency(c, exported = true) + + b.addDependency(lib) + c.addDependency(lib) + + a.production.assertDependenciesEqual(a.production, lib.classes, c.production, b.production) + b.production.assertDependenciesEqual(b.production, a.production, c.production, lib.classes) + c.production.assertDependenciesEqual(c.production, b.production, a.production, lib.classes) + } + + fun testSeveralModulesExportLibs() { + val (a, b, c) = modules() + + val lib1 = projectLibrary("lib1") + val lib2 = projectLibrary("lib2") + + a.addDependency(lib1, exported = true) + b.addDependency(lib2, exported = true) + c.addDependency(a) + c.addDependency(b) + + c.production.assertDependenciesEqual(c.production, a.production, lib1.classes, b.production, lib2.classes) + } + + fun testSeveralModulesExportSameLib() { + val (a, b, c) = modules() + + val lib = projectLibrary() + + a.addDependency(lib, exported = true) + b.addDependency(lib, exported = true) + c.addDependency(a) + c.addDependency(b) + + c.production.assertDependenciesEqual(c.production, a.production, lib.classes, b.production) + } + + fun testRuntimeDependency() { + val (a, b) = modules() + + b.addDependency(a, dependencyScope = DependencyScope.RUNTIME) + b.addDependency(projectLibrary(), dependencyScope = DependencyScope.RUNTIME) + + b.production.assertDependenciesEqual(b.production) + } + + fun testProvidedDependency() { + val (a, b) = modules() + val lib = projectLibrary() + + b.addDependency(a, dependencyScope = DependencyScope.PROVIDED) + b.addDependency(lib, dependencyScope = DependencyScope.PROVIDED) + + b.production.assertDependenciesEqual(b.production, a.production, lib.classes) + } + + fun testSimpleTestDependency() { + val (a, b) = modules() + b.addDependency(a, dependencyScope = DependencyScope.TEST) + + a.production.assertDependenciesEqual(a.production) + a.test.assertDependenciesEqual(a.test, a.production) + b.production.assertDependenciesEqual(b.production) + b.test.assertDependenciesEqual(b.test, b.production, a.test, a.production) + } + + fun testLibTestDependency() { + val a = module("a") + val lib = projectLibrary() + a.addDependency(lib, dependencyScope = DependencyScope.TEST) + + a.production.assertDependenciesEqual(a.production) + a.test.assertDependenciesEqual(a.test, a.production, lib.classes) + } + + fun testExportedTestDependency() { + val (a, b, c) = modules() + b.addDependency(a, exported = true) + c.addDependency(b, dependencyScope = DependencyScope.TEST) + + c.production.assertDependenciesEqual(c.production) + c.test.assertDependenciesEqual(c.test, c.production, b.test, b.production, a.test, a.production) + } + + fun testDependents() { + //NOTE: we do not differ between dependency kinds + val (a, b, c) = modules(name1 = "a", name2 = "b", name3 = "c") + val (d, e, f) = modules(name1 = "d", name2 = "e", name3 = "f") + + b.addDependency(a, exported = true) + + c.addDependency(a) + + d.addDependency(c, exported = true) + + e.addDependency(b) + + f.addDependency(d) + f.addDependency(e) + + + a.test.assertDependentsEqual(a.test, b.test, c.test, e.test) + a.production.assertDependentsEqual(a.production, a.test, b.production, b.test, c.production, c.test, e.production, e.test) + + b.test.assertDependentsEqual(b.test, e.test) + b.production.assertDependentsEqual(b.production, b.test, e.production, e.test) + + + c.test.assertDependentsEqual(c.test, d.test, f.test) + c.production.assertDependentsEqual(c.production, c.test, d.production, d.test, f.production, f.test) + + d.test.assertDependentsEqual(d.test, f.test) + d.production.assertDependentsEqual(d.production, d.test, f.production, f.test) + + e.test.assertDependentsEqual(e.test, f.test) + e.production.assertDependentsEqual(e.production, e.test, f.production, f.test) + + f.test.assertDependentsEqual(f.test) + f.production.assertDependentsEqual(f.production, f.test) + } + + fun testLibraryDependency1() { + val lib1 = projectLibrary("lib1") + val lib2 = projectLibrary("lib2") + + val module = module("module") + module.addDependency(lib1) + module.addDependency(lib2) + + lib1.classes.assertAdditionalLibraryDependencies(lib2.classes) + lib2.classes.assertAdditionalLibraryDependencies(lib1.classes) + } + + fun testLibraryDependency2() { + val lib1 = projectLibrary("lib1") + val lib2 = projectLibrary("lib2") + val lib3 = projectLibrary("lib3") + + val (a, b, c) = modules() + a.addDependency(lib1) + b.addDependency(lib2) + c.addDependency(lib3) + + c.addDependency(a) + c.addDependency(b) + + lib1.classes.assertAdditionalLibraryDependencies() + lib2.classes.assertAdditionalLibraryDependencies() + lib3.classes.assertAdditionalLibraryDependencies(lib1.classes, lib2.classes) + } + + fun testLibraryDependency3() { + val lib1 = projectLibrary("lib1") + val lib2 = projectLibrary("lib2") + val lib3 = projectLibrary("lib3") + + val (a, b) = modules() + a.addDependency(lib1) + b.addDependency(lib2) + + a.addDependency(lib3) + b.addDependency(lib3) + + lib1.classes.assertAdditionalLibraryDependencies(lib3.classes) + lib2.classes.assertAdditionalLibraryDependencies(lib3.classes) + lib3.classes.assertAdditionalLibraryDependencies(lib1.classes, lib2.classes) + } + + fun testRoots() { + val a = module("a", hasProductionRoot = true, hasTestRoot = false) + + val empty = module("empty", hasProductionRoot = false, hasTestRoot = false) + a.addDependency(empty) + + val b = module("b", hasProductionRoot = false, hasTestRoot = true) + b.addDependency(a) + + val c = module("c") + c.addDependency(b) + c.addDependency(a) + + assertNotNull(a.productionSourceInfo()) + assertNull(a.testSourceInfo()) + + assertNull(empty.productionSourceInfo()) + assertNull(empty.testSourceInfo()) + + assertNull(b.productionSourceInfo()) + assertNotNull(b.testSourceInfo()) + + b.test.assertDependenciesEqual(b.test, a.production) + c.test.assertDependenciesEqual(c.test, c.production, b.test, a.production) + c.production.assertDependenciesEqual(c.production, a.production) + } + + fun testCommonLibraryDoesNotDependOnPlatform() { + val stdlibCommon = stdlibCommon() + val stdlibJvm = stdlibJvm() + val stdlibJs = stdlibJs() + + val a = module("a") + a.addDependency(stdlibCommon) + a.addDependency(stdlibJvm) + + val b = module("b") + b.addDependency(stdlibCommon) + b.addDependency(stdlibJs) + + stdlibCommon.classes.assertAdditionalLibraryDependencies() + stdlibJvm.classes.assertAdditionalLibraryDependencies(stdlibCommon.classes) + stdlibJs.classes.assertAdditionalLibraryDependencies(stdlibCommon.classes) + } + + fun testScriptDependenciesForModule() { + val a = module("a") + val b = module("b") + + with(createFileInModule(a, "script.kts").moduleInfo) { + dependencies().contains(a.production) + dependencies().contains(a.test) + !dependencies().contains(b.production) + } + } + + fun testScriptDependenciesForProject() { + val a = module("a") + + val script = createFileInProject("script.kts").moduleInfo + + !script.dependencies().contains(a.production) + !script.dependencies().contains(a.test) + + script.dependencies().firstIsInstance() + } + + fun testSdkForScript() { + // The first known jdk will be used for scripting if there is no jdk in the project + runWriteAction { + addJdk(testRootDisposable, ::mockJdk6) + addJdk(testRootDisposable, ::mockJdk9) + + ProjectRootManager.getInstance(project).projectSdk = null + } + + val firstSDK = getProjectJdkTableSafe().allJdks.first() + + with(createFileInProject("script.kts").moduleInfo) { + dependencies().filterIsInstance().single { it.sdk == firstSDK } + } + } + + fun testSdkForScriptProjectSdk() { + runWriteAction { + addJdk(testRootDisposable, ::mockJdk6) + addJdk(testRootDisposable, ::mockJdk9) + + ProjectRootManager.getInstance(project).projectSdk = mockJdk9() + } + + with(createFileInProject("script.kts").moduleInfo) { + dependencies().filterIsInstance().single { it.sdk == mockJdk9() } + } + } + + fun testSdkForScriptModuleSdk() { + val a = module("a") + + runWriteAction { + addJdk(testRootDisposable, ::mockJdk6) + addJdk(testRootDisposable, ::mockJdk9) + + ProjectRootManager.getInstance(project).projectSdk = mockJdk6() + with(ModuleRootManager.getInstance(a).modifiableModel) { + sdk = mockJdk9() + commit() + } + } + + with(createFileInModule(a, "script.kts").moduleInfo) { + dependencies().filterIsInstance().first { it.sdk == mockJdk9() } + } + } + + private fun createFileInModule(module: Module, fileName: String, inTests: Boolean = false): VirtualFile { + val fileToCopyIO = createTempFile(fileName, "") + + for (contentEntry in ModuleRootManager.getInstance(module).contentEntries) { + for (sourceFolder in contentEntry.sourceFolders) { + if (((!inTests && !sourceFolder.isTestSource) || (inTests && sourceFolder.isTestSource)) && sourceFolder.file != null) { + return runWriteAction { + getVirtualFile(fileToCopyIO).copy(this, sourceFolder.file!!, fileName) + } + } + } + } + + error("Couldn't find source folder in ${module.name}") + } + + private fun createFileInProject(fileName: String): VirtualFile { + return runWriteAction { + getVirtualFile(createTempFile(fileName, "")).copy(this, project.baseDir, fileName) + } + } + + private fun Module.addDependency( + other: Module, + dependencyScope: DependencyScope = DependencyScope.COMPILE, + exported: Boolean = false + ) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported) + + private val VirtualFile.moduleInfo: IdeaModuleInfo + get() { + return PsiManager.getInstance(project).findFile(this)!!.getModuleInfo() + } + + private val Module.production: ModuleProductionSourceInfo + get() = productionSourceInfo()!! + + private val Module.test: ModuleTestSourceInfo + get() = testSourceInfo()!! + + private val LibraryEx.classes: LibraryInfo + get() = object : LibraryInfo(project!!, this) { + override val platform: TargetPlatform + get() = kind.platform + } + + private fun module(name: String, hasProductionRoot: Boolean = true, hasTestRoot: Boolean = true): Module { + return createModuleFromTestData(createTempDirectory().absolutePath, name, StdModuleTypes.JAVA, false).apply { + if (hasProductionRoot) + PsiTestUtil.addSourceContentToRoots(this, dir(), false) + if (hasTestRoot) + PsiTestUtil.addSourceContentToRoots(this, dir(), true) + } + } + + private fun dir() = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDirectory())!! + + private fun modules(name1: String = "a", name2: String = "b", name3: String = "c") = Triple(module(name1), module(name2), module(name3)) + + private fun IdeaModuleInfo.assertDependenciesEqual(vararg expected: IdeaModuleInfo) { + Assert.assertEquals(expected.toList(), this.dependencies()) + } + + private fun LibraryInfo.assertAdditionalLibraryDependencies(vararg expected: IdeaModuleInfo) { + Assert.assertEquals(this, dependencies().first()) + val dependenciesWithoutSelf = this.dependencies().drop(1) + UsefulTestCase.assertSameElements(dependenciesWithoutSelf, expected.toList()) + } + + private fun ModuleSourceInfo.assertDependentsEqual(vararg expected: ModuleSourceInfo) { + UsefulTestCase.assertSameElements(this.getDependentModules(), expected.toList()) + } + + private fun stdlibCommon(): LibraryEx = projectLibrary( + "kotlin-stdlib-common", + ForTestCompileRuntime.stdlibCommonForTests().jarRoot, + kind = CommonLibraryKind + ) + + private fun stdlibJvm(): LibraryEx = projectLibrary("kotlin-stdlib", ForTestCompileRuntime.runtimeJarForTests().jarRoot) + + private fun stdlibJs(): LibraryEx = projectLibrary( + "kotlin-stdlib-js", + ForTestCompileRuntime.runtimeJarForTests().jarRoot, + kind = JSLibraryKind + ) + + override fun setUp() { + super.setUp() + + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.203 b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.203 index 1b033c91798..ab9a09d4dfa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.203 +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.203 @@ -36,12 +36,11 @@ abstract class AbstractConfigureKotlinTest : PlatformTestCase() { override fun setUp() { super.setUp() - VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory()) + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) } @Throws(Exception::class) override fun tearDown() { - VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory()) PathMacros.getInstance().removeMacro(TEMP_DIR_MACRO_KEY) super.tearDown() diff --git a/idea/tests/org/jetbrains/kotlin/idea/repl/AbstractIdeReplCompletionTest.kt.203 b/idea/tests/org/jetbrains/kotlin/idea/repl/AbstractIdeReplCompletionTest.kt.203 new file mode 100644 index 00000000000..3c42d35a47b --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/repl/AbstractIdeReplCompletionTest.kt.203 @@ -0,0 +1,71 @@ +/* + * 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.repl + +import com.intellij.codeInsight.completion.CompletionType +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.PsiDocumentManager +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.console.KotlinConsoleKeeper +import org.jetbrains.kotlin.console.KotlinConsoleRunner +import org.jetbrains.kotlin.idea.completion.test.KotlinFixtureCompletionBaseTestCase +import org.jetbrains.kotlin.idea.completion.test.testCompletion +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractIdeReplCompletionTest : KotlinFixtureCompletionBaseTestCase() { + private var consoleRunner: KotlinConsoleRunner? = null + + override fun setUp() { + super.setUp() + consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!! + ScriptConfigurationManager.updateScriptDependenciesSynchronously(consoleRunner!!.consoleFile) + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) + } + + override fun tearDown() { + consoleRunner?.dispose() + consoleRunner = null + super.tearDown() + } + + override fun getPlatform() = JvmPlatforms.unspecifiedJvmPlatform + override fun defaultCompletionType() = CompletionType.BASIC + + override fun doTest(testPath: String) { + val runner = consoleRunner!! + val file = File(testPath) + val lines = file.readLines() + lines.prefixedWith(">> ").forEach { runner.successfulLine(it) } // not actually executing anything, only simulating + val codeSample = lines.prefixedWith("-- ").joinToString("\n") + + runWriteAction { + val editor = runner.consoleView.editorDocument + editor.setText(codeSample) + FileDocumentManager.getInstance().saveDocument(runner.consoleView.editorDocument) + PsiDocumentManager.getInstance(project).commitAllDocuments() + } + + myFixture.configureFromExistingVirtualFile(runner.consoleFile.virtualFile) + myFixture.editor.caretModel.moveToOffset(myFixture.editor.document.getLineEndOffset(0)) + + testCompletion(file.readText(), getPlatform(), { completionType, count -> myFixture.complete(completionType, count) }) + } + + private fun List.prefixedWith(prefix: String) = filter { it.startsWith(prefix) }.map { it.removePrefix(prefix) } + + override fun getProjectDescriptor(): LightProjectDescriptor = FullJdkProjectDescriptor +} + +private object FullJdkProjectDescriptor : KotlinWithJdkAndRuntimeLightProjectDescriptor() { + override fun getSdk() = PluginTestCaseBase.fullJdk() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/repl/IdeReplExecutionTest.kt.203 b/idea/tests/org/jetbrains/kotlin/idea/repl/IdeReplExecutionTest.kt.203 new file mode 100644 index 00000000000..799b2d9ecc0 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/repl/IdeReplExecutionTest.kt.203 @@ -0,0 +1,186 @@ +/* + * 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.repl + +import com.intellij.execution.console.LanguageConsoleImpl +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.testFramework.PlatformTestCase +import com.intellij.util.ThrowableRunnable +import com.intellij.util.ui.UIUtil +import org.jetbrains.kotlin.console.KotlinConsoleKeeper +import org.jetbrains.kotlin.console.KotlinConsoleRunner +import org.jetbrains.kotlin.idea.run.createLibraryWithLongPaths +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner +import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest +import org.jetbrains.kotlin.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.reflect.KMutableProperty0 +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(JUnit3WithIdeaConfigurationRunner::class) +@WithMutedInDatabaseRunTest +class IdeReplExecutionTest : PlatformTestCase() { + private lateinit var consoleRunner: KotlinConsoleRunner + private var commandsSent = 0 + + override fun setUp() { + super.setUp() + consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!! + } + + override fun tearDown() { + consoleRunner.dispose() + (this::consoleRunner as KMutableProperty0).set(null) + super.tearDown() + } + + override fun runTestRunnable(testRunnable: ThrowableRunnable) { + runTest { + super.runTestRunnable(testRunnable) + } + } + + private fun sendCommand(command: String) { + runWriteAction { consoleRunner.consoleView.editorDocument.setText(command) } + consoleRunner.executor.executeCommand() + commandsSent++ + } + + private fun checkOutput(expectedOutput: String) { + val output = getReplOutput(textOnTimeOut = { + "Only ${consoleRunner.commandHistory.processedEntriesCount} commands were processed" + }) { consoleRunner.commandHistory.processedEntriesCount >= commandsSent } + assertTrue(output.trim().endsWith(expectedOutput), "'$expectedOutput' should be printed but document text is:\n$output") + } + + private fun getReplOutput( + maxIterations: Int = 50, + sleepTime: Long = 500, + textOnTimeOut: () -> String, + predicate: () -> Boolean + ): String { + for (i in 1..maxIterations) { + UIUtil.dispatchAllInvocationEvents() + if (predicate()) { + return refreshAndGetHistoryEditorText() + } + Thread.sleep(sleepTime) + } + + return textOnTimeOut() + } + + private fun refreshAndGetHistoryEditorText(): String { + val consoleView = consoleRunner.consoleView as LanguageConsoleImpl + consoleView.flushDeferredText() + + return consoleView.historyViewer.document.text + } + + private fun testSimpleCommand(command: String, expectedOutput: String) { + sendCommand(command) + checkOutput(expectedOutput) + } + + @Test + fun testRunPossibility() { + val allOk = { x: String -> x.contains(":help for help") } + val hasErrors = { x: String -> + x.contains("Process finished with exit code 1") || x.contains("Exception in") || x.contains("Error") + } + + val output = getReplOutput(textOnTimeOut = { "Repl startup timed out" }) { + val editorText = refreshAndGetHistoryEditorText() + hasErrors(editorText) || allOk(editorText) + } + + assertFalse(hasErrors(output), "Cannot run kotlin repl") + assertTrue(allOk(output), "Successful run should contain text: ':help for help'") + assertFalse(consoleRunner.processHandler.isProcessTerminated, "Process accidentally terminated") + } + + @Test + fun testLongCommandLine() { + ModuleRootModificationUtil.addDependency(module, createLibraryWithLongPaths(project)) + + consoleRunner.dispose() + consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!! + + testRunPossibility() + } + + @Test + fun testOnePlusOne() = testSimpleCommand("1 + 1", "2") + + @Test + fun testPrintlnText() = "Hello, console world!".let { testSimpleCommand("println(\"$it\")", it) } + + @Test + fun testDivisionByZeroException() = testSimpleCommand("1 / 0", "java.lang.ArithmeticException: / by zero") + + @Test + fun testMultilineSupport() { + val printText = "Print in multiline!" + + sendCommand( + "fun f() {\n" + + " println(\"$printText\")\n" + + "}\n" + ) + sendCommand("f()") + + checkOutput(printText) + } + + @Test + fun testReadLineSingle() { + val readLineText = "ReadMe!" + + sendCommand("val a = readLine()") + sendCommand(readLineText) + sendCommand("a") + checkOutput(readLineText) + } + + @Test + fun testReadLineMultiple() { + val readLineTextA = "ReadMe A!" + val readLineTextB = "ReadMe B!" + + sendCommand( + "val a = readLine()\n" + + "val b = readLine()" + ) + sendCommand(readLineTextA) + sendCommand(readLineTextB) + + sendCommand("a") + checkOutput(readLineTextA) + sendCommand("b") + checkOutput(readLineTextB) + } + + @Test + fun testCorrectAfterError() { + val message = "MyMessage" + sendCommand("fun f() { println(x)\n println(y) ") + sendCommand("println(\"$message\")") + checkOutput(message) + } + + @Test + fun testMultipleErrorsHandling() { + val veryLongTextWithErrors = "println($);".repeat(30) + sendCommand(veryLongTextWithErrors) + sendCommand(veryLongTextWithErrors) + sendCommand(veryLongTextWithErrors) + sendCommand("println(\"OK\")") + checkOutput("OK") + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt.203 b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt.203 new file mode 100644 index 00000000000..174f3a97417 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt.203 @@ -0,0 +1,203 @@ +/* + * 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.stubs + +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleType +import com.intellij.openapi.module.StdModuleTypes +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.PersistentLibraryKind +import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.PsiFile +import com.intellij.testFramework.PsiTestUtil +import com.intellij.util.ThrowableRunnable +import org.jetbrains.kotlin.config.CompilerSettings +import org.jetbrains.kotlin.config.KotlinFacetSettings +import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.idea.facet.getOrCreateFacet +import org.jetbrains.kotlin.idea.facet.initializeIfNeeded +import org.jetbrains.kotlin.idea.test.* +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestJdkKind +import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest +import org.jetbrains.kotlin.test.runTest +import org.junit.Assert +import java.io.File + +@WithMutedInDatabaseRunTest +abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() { + + abstract override fun getTestDataPath(): String + + override fun setUp() { + super.setUp() + enableKotlinOfficialCodeStyle(project) + VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory()) + } + + fun module(name: String, jdk: TestJdkKind = TestJdkKind.MOCK_JDK, hasTestRoot: Boolean = false): Module { + val srcDir = testDataPath + "${getTestName(true)}/$name" + val moduleWithSrcRootSet = createModuleFromTestData(srcDir, name, StdModuleTypes.JAVA, true) + if (hasTestRoot) { + addRoot( + moduleWithSrcRootSet, + File(testDataPath + "${getTestName(true)}/${name}Test"), + true + ) + } + + ConfigLibraryUtil.configureSdk(moduleWithSrcRootSet, PluginTestCaseBase.addJdk(testRootDisposable) { PluginTestCaseBase.jdk(jdk) }) + + return moduleWithSrcRootSet + } + + override fun tearDown() = runAll( + ThrowableRunnable { disableKotlinOfficialCodeStyle(project) }, + ThrowableRunnable { super.tearDown() }, + ) + + public override fun createModule(path: String, moduleType: ModuleType<*>): Module { + return super.createModule(path, moduleType) + } + + override fun runTestRunnable(testRunnable: ThrowableRunnable) { + runTest { super.runTestRunnable(testRunnable) } + } + + fun addRoot(module: Module, sourceDirInTestData: File, isTestRoot: Boolean, transformContainedFiles: ((File) -> Unit)? = null) { + val tmpDir = createTempDirectory() + + // Preserve original root name. This might be useful for later matching of copied files to original ones + val tmpRootDir = File(tmpDir, sourceDirInTestData.name).also { it.mkdir() } + + FileUtil.copyDir(sourceDirInTestData, tmpRootDir) + + if (transformContainedFiles != null) { + tmpRootDir.listFiles().forEach(transformContainedFiles) + } + + val virtualTempDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tmpRootDir)!! + object : WriteCommandAction.Simple(project) { + override fun run() { + virtualTempDir.refresh(false, isTestRoot) + } + }.execute().throwException() + PsiTestUtil.addSourceRoot(module, virtualTempDir, isTestRoot) + } + + fun Module.addDependency( + other: Module, + dependencyScope: DependencyScope = DependencyScope.COMPILE, + exported: Boolean = false + ): Module = this.apply { ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported) } + + fun Module.addLibrary( + jar: File, + name: String = KotlinJdkAndLibraryProjectDescriptor.LIBRARY_NAME, + kind: PersistentLibraryKind<*>? = null + ) { + ConfigLibraryUtil.addLibrary(NewLibraryEditor().apply { + this.name = name + addRoot(VfsUtil.getUrlForLibraryRoot(jar), OrderRootType.CLASSES) + }, this, kind) + } + + fun Module.enableMultiPlatform(additionalCompilerArguments: String = "") { + createFacet() + val facetSettings = KotlinFacetSettingsProvider.getInstance(project)?.getInitializedSettings(this) + ?: error("Facet settings are not found") + + facetSettings.useProjectSettings = false + facetSettings.compilerSettings = CompilerSettings().apply { + additionalArguments += " -Xmulti-platform $additionalCompilerArguments" + } + } + + fun Module.enableCoroutines() { + createFacet() + val facetSettings = KotlinFacetSettingsProvider.getInstance(project)?.getInitializedSettings(this) + ?: error("Facet settings are not found") + + facetSettings.useProjectSettings = false + facetSettings.coroutineSupport = LanguageFeature.State.ENABLED + } + + protected fun checkFiles( + findFiles: () -> List, + check: () -> Unit + ) { + var atLeastOneFile = false + findFiles().forEach { file -> + configureByExistingFile(file.virtualFile!!) + atLeastOneFile = true + check() + } + Assert.assertTrue(atLeastOneFile) + } +} + +fun Module.createFacet( + platformKind: TargetPlatform? = null, + useProjectSettings: Boolean = true +) { + createFacetWithAdditionalSetup(platformKind, useProjectSettings) { } +} + +fun Module.createMultiplatformFacetM1( + platformKind: TargetPlatform? = null, + useProjectSettings: Boolean = true, + implementedModuleNames: List, + pureKotlinSourceFolders: List +) { + createFacetWithAdditionalSetup(platformKind, useProjectSettings) { + this.implementedModuleNames = implementedModuleNames + this.pureKotlinSourceFolders = pureKotlinSourceFolders + } +} + +fun Module.createMultiplatformFacetM3( + platformKind: TargetPlatform? = null, + useProjectSettings: Boolean = true, + dependsOnModuleNames: List, + pureKotlinSourceFolders: List +) { + createFacetWithAdditionalSetup(platformKind, useProjectSettings) { + this.dependsOnModuleNames = dependsOnModuleNames + this.isHmppEnabled = true + this.pureKotlinSourceFolders = pureKotlinSourceFolders + } +} + +private fun Module.createFacetWithAdditionalSetup( + platformKind: TargetPlatform?, + useProjectSettings: Boolean, + additionalSetup: KotlinFacetSettings.() -> Unit +) { + WriteAction.run { + val modelsProvider = IdeModifiableModelsProviderImpl(project) + with(getOrCreateFacet(modelsProvider, useProjectSettings).configuration.settings) { + initializeIfNeeded( + this@createFacetWithAdditionalSetup, + modelsProvider.getModifiableRootModel(this@createFacetWithAdditionalSetup), + platformKind + ) + additionalSetup() + } + modelsProvider.commit() + } +} \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt.203 b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt.203 new file mode 100644 index 00000000000..aa87f659f90 --- /dev/null +++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt.203 @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.j2k + +import com.intellij.openapi.roots.LanguageLevelProjectExtension +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.pom.java.LanguageLevel +import com.intellij.testFramework.LightPlatformTestCase +import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.DEBUG_LOG_ENABLE_PerModulePackageCache +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.invalidateLibraryCache +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractJavaToKotlinConverterTest : KotlinLightCodeInsightFixtureTestCase() { + override fun setUp() { + super.setUp() + + project.DEBUG_LOG_ENABLE_PerModulePackageCache = true + + val testName = getTestName(false) + if (testName.contains("Java8") || testName.contains("java8")) { + LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_1_8 + } + + VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory()) + + invalidateLibraryCache(project) + + addFile("KotlinApi.kt", "kotlinApi") + addFile("JavaApi.java", "javaApi") + } + + override fun tearDown() { + project.DEBUG_LOG_ENABLE_PerModulePackageCache = false + super.tearDown() + } + + protected fun addFile(fileName: String, dirName: String? = null) { + addFile(File("j2k/testData/$fileName"), dirName) + } + + protected fun addFile(file: File, dirName: String?): VirtualFile { + return addFile(FileUtil.loadFile(file, true), file.name, dirName) + } + + protected fun addFile(text: String, fileName: String, dirName: String?): VirtualFile { + return runWriteAction { + val root = LightPlatformTestCase.getSourceRoot()!! + val virtualDir = dirName?.let { + root.findChild(it) ?: root.createChildDirectory(null, it) + } ?: root + val virtualFile = virtualDir.createChildData(null, fileName) + virtualFile.getOutputStream(null)!!.writer().use { it.write(text) } + virtualFile + } + } + + protected fun deleteFile(virtualFile: VirtualFile) { + runWriteAction { virtualFile.delete(this) } + } +} + diff --git a/js/js.engines/src/org/jetbrains/kotlin/js/engine/ScriptEngineNashorn.kt b/js/js.engines/src/org/jetbrains/kotlin/js/engine/ScriptEngineNashorn.kt index c3c089a85a0..c5e86590824 100644 --- a/js/js.engines/src/org/jetbrains/kotlin/js/engine/ScriptEngineNashorn.kt +++ b/js/js.engines/src/org/jetbrains/kotlin/js/engine/ScriptEngineNashorn.kt @@ -2,7 +2,7 @@ * 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. */ - +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package org.jetbrains.kotlin.js.engine import jdk.nashorn.api.scripting.NashornScriptEngineFactory