diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt index 68e2f11e4617..e01cc6215729 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt @@ -3,11 +3,14 @@ package com.intellij.openapi.externalSystem.service.project.manage import com.intellij.ide.projectView.actions.MarkRootActionBase import com.intellij.openapi.Disposable +import com.intellij.openapi.application.TransactionGuard import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.externalSystem.util.PathPrefixTreeMapImpl import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.* @@ -20,13 +23,12 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage private var isDisposed = false private val mutex = Any() private val postponedSourceFolderCreator = PostponedSourceFolderCreator() - private val sourceFolders = THashMap(FileUtil.PATH_HASHING_STRATEGY) + private val sourceFolders = PathPrefixTreeMapImpl() private val sourceFoldersByModule = THashMap() override fun addSourceFolder(module: Module, url: String, type: JpsModuleSourceRootType<*>) { - val sourceFolder = SourceFolderModel(module, type, "") synchronized(mutex) { - sourceFolders[url] = sourceFolder + sourceFolders[url] = SourceFolderModel(module, url, type, "") val moduleModel = sourceFoldersByModule.getOrPut(module.name) { ModuleModel(module).also { Disposer.register(module, it) @@ -34,6 +36,10 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage } moduleModel.sourceFolders.add(url) } + TransactionGuard.getInstance().submitTransactionLater(this, Runnable { + val virtualFileManager = VirtualFileManager.getInstance() + virtualFileManager.refreshAndFindFileByUrl(url) + }) } override fun setSourceFolderPackagePrefix(url: String, packagePrefix: String) { @@ -57,42 +63,60 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage virtualFileManager.removeVirtualFileListener(postponedSourceFolderCreator) } - private fun remove(url: String): SourceFolderModel? { - return synchronized(mutex) { - sourceFolders.remove(url) - } - } - fun isDisposed() = isDisposed fun getSourceFolders(moduleName: String) = synchronized(mutex) { sourceFoldersByModule[moduleName]?.sourceFolders } + private fun unsafeRemoveSourceFolder(url: String) { + val sourceFolder = sourceFolders.remove(url) ?: return + val module = sourceFolder.module + val moduleModel = sourceFoldersByModule[module.name] ?: return + val sourceFolders = moduleModel.sourceFolders + sourceFolders.remove(url) + if (sourceFolders.isEmpty()) { + sourceFoldersByModule.remove(module.name) + } + } + private inner class PostponedSourceFolderCreator : VirtualFileListener { override fun fileCreated(event: VirtualFileEvent) { + val sourceFoldersToChange = ArrayList() + val virtualFileManager = VirtualFileManager.getInstance() + synchronized(mutex) { + for (sourceFolder in sourceFolders.getAllDescendants(event.file.url)) { + val sourceFolderFile = ExternalSystemApiUtil.doWriteAction(Computable { + virtualFileManager.refreshAndFindFileByUrl(sourceFolder.url) + }) + if (sourceFolderFile != null && sourceFolderFile.isValid) { + sourceFoldersToChange.add(sourceFolder) + unsafeRemoveSourceFolder(sourceFolder.url) + } + } + } ExternalSystemApiUtil.executeProjectChangeAction(false, object : DisposeAwareProjectChange(project) { override fun execute() { - val sourceFolderUrl = event.file.url - val (module, type, packagePrefix) = remove(sourceFolderUrl) ?: return - val moduleManager = ModuleRootManager.getInstance(module) - val modifiableModuleModel = moduleManager.modifiableModel - try { - val contentEntry = MarkRootActionBase.findContentEntry(modifiableModuleModel, event.file) - if (contentEntry != null) { - val sourceFolder = contentEntry.addSourceFolder(sourceFolderUrl, type) - sourceFolder.packagePrefix = packagePrefix + for ((module, url, type, packagePrefix) in sourceFoldersToChange) { + val moduleManager = ModuleRootManager.getInstance(module) + val modifiableModuleModel = moduleManager.modifiableModel + try { + val contentEntry = MarkRootActionBase.findContentEntry(modifiableModuleModel, event.file) + if (contentEntry != null) { + val sourceFolder = contentEntry.addSourceFolder(url, type) + sourceFolder.packagePrefix = packagePrefix + } + } + finally { + modifiableModuleModel.commit() } - } - finally { - modifiableModuleModel.commit() } } }) } } - private data class SourceFolderModel(val module: Module, val type: JpsModuleSourceRootType<*>, var packagePrefix: String) + private data class SourceFolderModel(val module: Module, val url: String, val type: JpsModuleSourceRootType<*>, var packagePrefix: String) private inner class ModuleModel(val module: Module, val sourceFolders: MutableSet) : Disposable { constructor(module: Module) : this(module, THashSet(FileUtil.PATH_HASHING_STRATEGY)) diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMap.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMap.kt new file mode 100644 index 000000000000..d33f2ee3bdda --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMap.kt @@ -0,0 +1,34 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.externalSystem.util + +/** + * [PrefixTreeMap] uses keys, that is specified by the file system paths. + * @see PrefixTreeMap + */ +interface PathPrefixTreeMap : PrefixTreeMap { + + /** + * @see PrefixTreeMap.get + */ + operator fun get(path: String): V? + + /** + * @see PrefixTreeMap.set + */ + operator fun set(path: String, value: V): V? + + /** + * @see PrefixTreeMap.remove + */ + fun remove(path: String): V? + + /** + * @see PrefixTreeMap.contains + */ + fun contains(path: String): Boolean + + /** + * @see PrefixTreeMap.getAllDescendants + */ + fun getAllDescendants(path: String): List +} \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMapImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMapImpl.kt new file mode 100644 index 000000000000..3745a9b5e30d --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PathPrefixTreeMapImpl.kt @@ -0,0 +1,25 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.externalSystem.util + +import com.intellij.openapi.util.io.FileUtil + +class PathPrefixTreeMapImpl( + private val pathSeparator: String = "/", + private val removeLastSlash: Boolean = true +) : PathPrefixTreeMap, PrefixTreeMapImpl(FileUtil.PATH_HASHING_STRATEGY) { + + override operator fun get(path: String): V? = get(path.toPrefixList()) + + override operator fun set(path: String, value: V): V? = set(path.toPrefixList(), value) + + override fun remove(path: String): V? = remove(path.toPrefixList()) + + override fun contains(path: String): Boolean = contains(path.toPrefixList()) + + override fun getAllDescendants(path: String): List = getAllDescendants(path.toPrefixList()) + + private fun String.toPrefixList(): List { + val path = if (removeLastSlash) removeSuffix(pathSeparator) else this + return path.split(pathSeparator) + } +} \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMap.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMap.kt new file mode 100644 index 000000000000..a624fa9999c5 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMap.kt @@ -0,0 +1,49 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.externalSystem.util + +/** + * Map for fast finding values by the prefix of them keys + */ +interface PrefixTreeMap { + + /** + * Gets value from the storage by the specified [path] + * + * @param path is key identificator + * @return stored value with the specified [path], null if [path] not found + */ + operator fun get(path: List): V? + + /** + * Sets value in the storage by the specified [path] + * + * @param path is key identificator + * @param value is value to store + * @return previous stored value with the specified [path], null if previous [path] not found + */ + operator fun set(path: List, value: V): V? + + /** + * Removes value from the storage by the specified [path] + * + * @param path is key identificator + * @return stored value with the specified [path], null if stored [path] not found + */ + fun remove(path: List): V? + + /** + * Checks existence of [path] in the storage + * + * @param path is key identificator + * @return result of existence checking + */ + fun contains(path: List): Boolean + + /** + * Gets all values with a key, for which [path] is an ancestor + * + * @param path is key identificator + * @return list of stored values, [emptyList] if [path] not found + */ + fun getAllDescendants(path: List): List +} \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMapImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMapImpl.kt new file mode 100644 index 000000000000..3ebc6e522bce --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/PrefixTreeMapImpl.kt @@ -0,0 +1,93 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.externalSystem.util + +import com.intellij.util.containers.FList +import gnu.trove.THashMap +import gnu.trove.TObjectHashingStrategy + +open class PrefixTreeMapImpl(private val strategy: TObjectHashingStrategy? = null) : PrefixTreeMap { + + private val root = Node() + + override operator fun get(path: List) = root.get(path.toFList())?.getValue() + + override operator fun set(path: List, value: V) = root.put(path.toFList(), value) + + override fun remove(path: List) = root.remove(path.toFList()) + + override fun contains(path: List) = root.contains(path.toFList()) + + override fun getAllDescendants(path: List) = root.get(path.toFList())?.getAllDescendants() ?: emptyList() + + private inner class Node { + private val children = strategy?.let { THashMap(it) } ?: THashMap() + private val isLeaf get() = children.isEmpty + private val isInvalid get() = isLeaf && !isPresent + private var isPresent: Boolean = false + private var value: V? = null + + fun getValue() = value + + fun put(path: FList, value: V): V? { + val (head, tail) = path + val child = children.getOrPut(head) { Node() } + if (tail.isEmpty()) { + val previousValue = child.value + child.value = value + child.isPresent = true + return previousValue + } + else return child.put(tail, value) + } + + fun remove(path: FList): V? { + val (head, tail) = path + val child = children[head] ?: return null + if (tail.isEmpty()) { + val value = child.value + child.value = null + child.isPresent = false + return value + } + else { + val result = child.remove(tail) + if (child.isInvalid) { + children.remove(head) + } + return result + } + } + + fun contains(path: FList): Boolean { + val (head, tail) = path + val child = children[head] ?: return false + return when { + tail.isEmpty() -> child.isPresent + else -> child.contains(tail) + } + } + + fun get(path: FList): Node? { + val (head, tail) = path + val child = children[head] ?: return null + return when { + tail.isEmpty() -> child + else -> child.get(tail) + } + } + + fun getAllDescendants(): List { + val result = children.flatMap { it.value.getAllDescendants() }.toMutableList() + value?.let { result.add(it) } + return result + } + } + + companion object { + private operator fun FList.component1() = head + + private operator fun FList.component2() = tail + + private fun List.toFList() = FList.createFromReversed(asReversed()) + } +} \ No newline at end of file diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/PathPrefixTreeMapImplTest.kt b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/PathPrefixTreeMapImplTest.kt new file mode 100644 index 000000000000..7fdea6a05d3f --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/PathPrefixTreeMapImplTest.kt @@ -0,0 +1,241 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.externalSystem.service.project.manage + +import com.intellij.openapi.externalSystem.util.PathPrefixTreeMapImpl +import com.intellij.testFramework.UsefulTestCase +import org.junit.Test + +class PathPrefixTreeMapImplTest : UsefulTestCase() { + + @Test + fun `test map filling`() { + val map = PathPrefixTreeMapImpl() + map["C://path/to/my/dir3"] = 30 + map["C://path/to/my/dir4"] = 10 + map["C://path/to/dir1"] = 11 + map["C://path/to/dir2"] = 21 + map["C://path/to/my"] = 43 + map["C://path"] = 13 + assertEquals(map["C://path/to/my/dir1"], null) + assertEquals(map["C://path/to/my/dir2"], null) + assertEquals(map["C://path/to/my/dir3"], 30) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1"], 11) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3"], null) + assertEquals(map["C://path/to/dir4"], null) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertFalse(map.contains("C://path/to/my/dir1")) + assertFalse(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertFalse(map.contains("C://path/to/dir3")) + assertFalse(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + map["C://path/to/my/dir1"] = 10 + map["C://path/to/my/dir2"] = 20 + map["C://path/to/dir3"] = 30 + map["C://path/to/dir4"] = 11 + assertEquals(map["C://path/to/my/dir1"], 10) + assertEquals(map["C://path/to/my/dir2"], 20) + assertEquals(map["C://path/to/my/dir3"], 30) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1"], 11) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3"], 30) + assertEquals(map["C://path/to/dir4"], 11) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertTrue(map.contains("C://path/to/my/dir1")) + assertTrue(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertTrue(map.contains("C://path/to/dir3")) + assertTrue(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + } + + @Test + fun `test map removes`() { + val map = PathPrefixTreeMapImpl() + map["C://path/to/my/dir1"] = 10 + map["C://path/to/my/dir2"] = 20 + map["C://path/to/my/dir3"] = 30 + map["C://path/to/my/dir4"] = 10 + map["C://path/to/dir1"] = 11 + map["C://path/to/dir2"] = 21 + map["C://path/to/dir3"] = 30 + map["C://path/to/dir4/"] = 11 + map["C://path/to/my"] = 43 + map["C://path"] = 13 + assertEquals(map["C://path/to/my/dir1"], 10) + assertEquals(map["C://path/to/my/dir2"], 20) + assertEquals(map["C://path/to/my/dir3"], 30) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1"], 11) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3"], 30) + assertEquals(map["C://path/to/dir4"], 11) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertTrue(map.contains("C://path/to/my/dir1")) + assertTrue(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertTrue(map.contains("C://path/to/dir3")) + assertTrue(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + map.remove("C://path/to/my/dir1/") + map.remove("C://path/to/my/dir2") + map.remove("C://path/to/dir3") + map.remove("C://path/to/dir4") + assertEquals(map["C://path/to/my/dir1"], null) + assertEquals(map["C://path/to/my/dir2"], null) + assertEquals(map["C://path/to/my/dir3"], 30) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1"], 11) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3/"], null) + assertEquals(map["C://path/to/dir4"], null) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertFalse(map.contains("C://path/to/my/dir1")) + assertFalse(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertFalse(map.contains("C://path/to/dir3")) + assertFalse(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + } + + + @Test + fun `test containing nullable values`() { + val map = PathPrefixTreeMapImpl() + map["C://path/to/my/dir1"] = null + map["C://path/to/my/dir2"] = 20 + map["C://path/to/my/dir3/"] = null + map["C://path/to/my/dir4/"] = 10 + map["C://path/to/dir1"] = null + map["C://path/to/dir2"] = 21 + map["C://path/to/dir3"] = null + map["C://path/to/dir4"] = 11 + map["C://path/to/my"] = 43 + map["C://path"] = 13 + assertEquals(map["C://path/to/my/dir1"], null) + assertEquals(map["C://path/to/my/dir2"], 20) + assertEquals(map["C://path/to/my/dir3"], null) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1"], null) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3"], null) + assertEquals(map["C://path/to/dir4/"], 11) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertTrue(map.contains("C://path/to/my/dir1")) + assertTrue(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4/")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertTrue(map.contains("C://path/to/dir3")) + assertTrue(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + map.remove("C://path/to/my/dir1") + map.remove("C://path/to/my/dir2") + map.remove("C://path/to/dir3") + map.remove("C://path/to/dir4") + assertEquals(map["C://path/to/my/dir1"], null) + assertEquals(map["C://path/to/my/dir2"], null) + assertEquals(map["C://path/to/my/dir3"], null) + assertEquals(map["C://path/to/my/dir4"], 10) + assertEquals(map["C://path/to/dir1/"], null) + assertEquals(map["C://path/to/dir2"], 21) + assertEquals(map["C://path/to/dir3"], null) + assertEquals(map["C://path/to/dir4"], null) + assertEquals(map["C://path/to/my"], 43) + assertEquals(map["C://path"], 13) + assertFalse(map.contains("C://path/to/my/dir1/")) + assertFalse(map.contains("C://path/to/my/dir2")) + assertTrue(map.contains("C://path/to/my/dir3")) + assertTrue(map.contains("C://path/to/my/dir4")) + assertTrue(map.contains("C://path/to/dir1")) + assertTrue(map.contains("C://path/to/dir2")) + assertFalse(map.contains("C://path/to/dir3")) + assertFalse(map.contains("C://path/to/dir4")) + assertTrue(map.contains("C://path/to/my")) + assertTrue(map.contains("C://path")) + } + + @Test + fun `test get all elements under dir`() { + val map = PathPrefixTreeMapImpl() + map["C://path/to/my/dir1/"] = 10 + map["C://path/to/my/dir2"] = 20 + map["C://path/to/my/dir3/"] = 30 + map["C://path/to/my/dir4"] = 10 + map["C://path/to/dir1"] = 11 + map["C://path/to/dir2/"] = 21 + map["C://path/to/dir3"] = 30 + map["C://path/to/dir4/"] = 11 + map["C://path/to/my"] = 43 + map["C://path"] = 13 + val underMy = map.getAllDescendants("C://path/to/my").toSet() + assertEquals(setOf(10, 20, 30, 10, 43), underMy) + val underMyDir = map.getAllDescendants("C://path/to/my/").toSet() + assertEquals(setOf(10, 20, 30, 10, 43), underMyDir) + val underTo = map.getAllDescendants("C://path/to").toSet() + assertEquals(setOf(10, 20, 30, 10, 43, 11, 21, 30, 11, 43), underTo) + val underToDir = map.getAllDescendants("C://path/to/").toSet() + assertEquals(setOf(10, 20, 30, 10, 43, 11, 21, 30, 11, 43), underToDir) + val underPath = map.getAllDescendants("C://path").toSet() + assertEquals(setOf(10, 20, 30, 10, 43, 11, 21, 30, 11, 43, 13), underPath) + val underProto = map.getAllDescendants("C:/").toSet() + assertEquals(setOf(10, 20, 30, 10, 43, 11, 21, 30, 11, 43, 13), underProto) + } + + @Test + fun `test usage with unix paths`() { + val map = PathPrefixTreeMapImpl() + map["/path/to/my/dir1/"] = 10 + map["/path/to/my/dir2"] = 20 + map["/path/to/my/dir3/"] = 30 + assertEquals(10, map.remove("/path/to/my/dir1/")) + assertEquals(null, map.remove("/path/to/my/dir1/")) + map["/path/to/my/dir4"] = 10 + map["/path/to/dir1"] = 11 + map["/path/to/dir2/"] = 21 + assertEquals(11, map.remove("/path/to/dir1/")) + map["/path/to/dir3"] = 30 + assertEquals(10, map.remove("/path/to/my/dir4/")) + map["/path/to/dir4/"] = 11 + assertEquals(null, map.remove("/path")) + map["/path/to/my"] = 43 + map["/path"] = 13 + assertEquals(13, map.remove("/path")) + assertFalse(map.contains("/path/to/my/dir1")) + assertTrue(map.contains("/path/to/my/dir2")) + assertTrue(map.contains("/path/to/my/dir3")) + assertFalse(map.contains("/path/to/my/dir4/")) + assertFalse(map.contains("/path/to/dir1")) + assertTrue(map.contains("/path/to/dir2/")) + assertTrue(map.contains("/path/to/dir3")) + assertTrue(map.contains("/path/to/dir4/")) + assertTrue(map.contains("/path/to/my")) + assertFalse(map.contains("/path")) + } +} \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleSettingsImportingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleSettingsImportingTest.java index 10872dcec3fc..4f1c830c553f 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleSettingsImportingTest.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleSettingsImportingTest.java @@ -417,7 +417,6 @@ public class GradleSettingsImportingTest extends GradleImportingTestCase { @Test public void testRemovingSourceFolderManagerMemLeaking() throws IOException { - refreshRecursively(myProjectRoot); SourceFolderManagerImpl sourceFolderManager = (SourceFolderManagerImpl)SourceFolderManager.getInstance(myProject); String javaSourcePath = FileUtil.toCanonicalPath(myProjectRoot.getPath() + "/java"); String javaSourceUrl = VfsUtilCore.pathToUrl(javaSourcePath); @@ -464,9 +463,6 @@ public class GradleSettingsImportingTest extends GradleImportingTestCase { @Ignore // Remove after published plugin ext with package prefix configuration @Test public void testPostponedImportPackagePrefix() throws IOException { - refreshRecursively(myProjectRoot); - ApplicationManager.getApplication().invokeAndWait(() -> { - }); createProjectSubFile("src/main/java/Main.java", ""); importProject( new GradleBuildScriptBuilderEx() @@ -487,9 +483,6 @@ public class GradleSettingsImportingTest extends GradleImportingTestCase { assertSourceNotExists("project.main", "src/main/kotlin"); assertSourceNotExists("project.test", "src/test/java"); createProjectSubFile("src/main/kotlin/Main.kt", ""); - refreshRecursively(myProjectRoot); - ApplicationManager.getApplication().invokeAndWait(() -> { - }); assertSourcePackagePrefix("project.main", "src/main/java", "prefix.package.some"); assertSourcePackagePrefix("project.main", "src/main/kotlin", "prefix.package.other"); assertSourceNotExists("project.test", "src/test/java");