From bb98caa1ca8c28c8153327bb580be2aec96c1b73 Mon Sep 17 00:00:00 2001 From: Jakub Chrzanowski Date: Fri, 6 Oct 2023 13:49:06 +0200 Subject: [PATCH] Fixed: ConcurrentModificationException in UnignoreFileGroupAction#GetChildren #860 --- CHANGELOG.md | 1 + .../mobi/hsz/idea/gitignore/IgnoreManager.kt | 17 ++++++++++------- .../gitignore/actions/IgnoreFileGroupAction.kt | 7 ++++--- .../idea/gitignore/util/CachedConcurrentMap.kt | 2 +- src/main/resources/META-INF/plugin.xml | 4 ++-- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ba00029..ee157ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fixed `com.intellij.openapi.util.TraceableDisposable$DisposalException: Double release of editor` - Improve module root detection in Rider - Fixed issue when starring the template, marks both `gitignore` and `toptal` entries [\#844](https://github.com/hsz/idea-gitignore/issues/844) +- Fixed ConcurrentModificationException in UnignoreFileGroupAction#GetChildren [\#860](https://github.com/hsz/idea-gitignore/issues/860) ## [4.5.1] - 2023-06-22 - Fixed `Slow operations are prohibited on EDT` [\#831](https://github.com/hsz/idea-gitignore/issues/831) diff --git a/src/main/kotlin/mobi/hsz/idea/gitignore/IgnoreManager.kt b/src/main/kotlin/mobi/hsz/idea/gitignore/IgnoreManager.kt index fb761d98..9f93df96 100644 --- a/src/main/kotlin/mobi/hsz/idea/gitignore/IgnoreManager.kt +++ b/src/main/kotlin/mobi/hsz/idea/gitignore/IgnoreManager.kt @@ -63,8 +63,9 @@ class IgnoreManager(private val project: Project) : DumbAware, Disposable { private val commonRunnableListeners = CommonRunnableListeners(debouncedStatusesChanged) private var messageBus = project.messageBus.connect(this) - private val cachedIgnoreFilesIndex = - CachedConcurrentMap.create> { key -> IgnoreFilesIndex.getEntries(project, key) } + private val cachedIgnoreFilesIndex = CachedConcurrentMap.create> { + IgnoreFilesIndex.getEntries(project, it) + } private val expiringStatusCache = ExpiringMap(Time.SECOND) @@ -98,11 +99,13 @@ class IgnoreManager(private val project: Project) : DumbAware, Disposable { } private fun handleEvent(event: VFileEvent) { - val fileType = event.file?.fileType - if (fileType is IgnoreFileType) { - cachedIgnoreFilesIndex.remove(fileType) - expiringStatusCache.clear() - debouncedStatusesChanged.run() + ApplicationManager.getApplication().runReadAction { + val fileType = event.file?.fileType + if (fileType is IgnoreFileType) { + cachedIgnoreFilesIndex.remove(fileType) + expiringStatusCache.clear() + debouncedStatusesChanged.run() + } } } } diff --git a/src/main/kotlin/mobi/hsz/idea/gitignore/actions/IgnoreFileGroupAction.kt b/src/main/kotlin/mobi/hsz/idea/gitignore/actions/IgnoreFileGroupAction.kt index 6f7411d2..84df49f1 100644 --- a/src/main/kotlin/mobi/hsz/idea/gitignore/actions/IgnoreFileGroupAction.kt +++ b/src/main/kotlin/mobi/hsz/idea/gitignore/actions/IgnoreFileGroupAction.kt @@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.addIfNotNull import mobi.hsz.idea.gitignore.IgnoreBundle import mobi.hsz.idea.gitignore.file.type.IgnoreFileType @@ -27,7 +28,7 @@ open class IgnoreFileGroupAction( ) : ActionGroup() { /** List of suitable Gitignore [VirtualFile]s that can be presented in an IgnoreFile action. */ - private val files = mutableMapOf>() + private val files = ContainerUtil.createConcurrentWeakMap>() @PropertyKey(resourceBundle = IgnoreBundle.BUNDLE_NAME) private val presentationTextSingleKey: String @@ -65,7 +66,7 @@ open class IgnoreFileGroupAction( // skip already bundled languages for ignore action .filterNot { this !is UnignoreFileGroupAction && (it is GitLanguage || it is MercurialLanguage) } .map { it.fileType } - .forEach { files[it] = getSuitableIgnoreFiles(project, it, file).reversed() } + .forEach { files[it.languageName] = getSuitableIgnoreFiles(project, it, file).reversed() } } catch (e: ExternalFileException) { presentation.isVisible = false } @@ -100,7 +101,7 @@ open class IgnoreFileGroupAction( } templatePresentation.apply { - icon = key.icon + icon = IgnoreBundle.LANGUAGES[key]?.icon text = name } } diff --git a/src/main/kotlin/mobi/hsz/idea/gitignore/util/CachedConcurrentMap.kt b/src/main/kotlin/mobi/hsz/idea/gitignore/util/CachedConcurrentMap.kt index 26c6f77e..e9c00271 100644 --- a/src/main/kotlin/mobi/hsz/idea/gitignore/util/CachedConcurrentMap.kt +++ b/src/main/kotlin/mobi/hsz/idea/gitignore/util/CachedConcurrentMap.kt @@ -9,7 +9,7 @@ import java.util.concurrent.ConcurrentMap */ class CachedConcurrentMap private constructor(private val fetcher: DataFetcher) { - private val map: ConcurrentMap = ContainerUtil.createConcurrentWeakMap() + private val map: ConcurrentMap = ContainerUtil.createConcurrentWeakMap() companion object { fun create(fetcher: DataFetcher) = CachedConcurrentMap(fetcher) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index cc6f116d..d16c7ab5 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -17,8 +17,8 @@ file="colorSchemes/IgnoreDarcula.xml" scheme="Darcula"/> - +