From 5fa64dce4b6918a520a7e059f93ac57f4e6893ed Mon Sep 17 00:00:00 2001 From: "Maxim.Kolmakov" Date: Thu, 17 Oct 2024 18:27:38 +0200 Subject: [PATCH] IJPL-164393 Add freeze analyzer to "Analyze Stacktrace or Thread Dump" action GitOrigin-RevId: e9f9d6527b1768b87f59b19e03df5456aadcf81e --- platform/lang-impl/api-dump-experimental.txt | 4 ++ .../unscramble/AnalyzeStacktraceUtil.java | 21 ++++++++-- .../StacktraceTabContentProvider.java | 12 ++++++ .../src/META-INF/LangExtensionPoints.xml | 2 + .../resources/intellij.devkit.stacktrace.xml | 2 + .../devkit/stacktrace/FreezeDescriptor.kt | 39 +++++++++++++++++++ .../stacktrace/editor/StackTraceFileEditor.kt | 16 +------- 7 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/unscramble/StacktraceTabContentProvider.java create mode 100644 plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/FreezeDescriptor.kt diff --git a/platform/lang-impl/api-dump-experimental.txt b/platform/lang-impl/api-dump-experimental.txt index eeb49089900b..1b73ab3c725b 100644 --- a/platform/lang-impl/api-dump-experimental.txt +++ b/platform/lang-impl/api-dump-experimental.txt @@ -810,6 +810,10 @@ f:com.intellij.task.impl.ProjectTaskManagerImpl - a:getRequestedTasks(java.lang.Class):java.util.List f:com.intellij.testIntegration.TestFinderHelper - *s:navigateToTestImmediately(com.intellij.psi.PsiElement):Z +f:com.intellij.unscramble.AnalyzeStacktraceUtil +- *sf:EP_CONTENT_PROVIDER:com.intellij.openapi.extensions.ProjectExtensionPointName +*:com.intellij.unscramble.StacktraceTabContentProvider +- a:createRunTabDescriptor(com.intellij.openapi.project.Project,java.lang.String):com.intellij.execution.ui.RunContentDescriptor *f:com.intellij.util.gist.GistAstMarker - (com.intellij.openapi.fileTypes.FileType,java.lang.String,kotlin.jvm.functions.Function1):V - f:accepts(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile):Z diff --git a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java index ae8790507e7f..50f3ac1c9428 100644 --- a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java +++ b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.NlsContexts; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.concurrency.ThreadingAssertions; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,6 +37,9 @@ import static com.intellij.openapi.application.ex.ClipboardUtil.getTextInClipboa public final class AnalyzeStacktraceUtil { public static final ProjectExtensionPointName EP_NAME = new ProjectExtensionPointName<>("com.intellij.analyzeStacktraceFilter"); + @ApiStatus.Experimental + public static final ProjectExtensionPointName EP_CONTENT_PROVIDER = + new ProjectExtensionPointName<>("com.intellij.analyzeStacktraceRunContentProvider"); private AnalyzeStacktraceUtil() { } @@ -51,7 +55,10 @@ public final class AnalyzeStacktraceUtil { JComponent createConsoleComponent(ConsoleView consoleView, DefaultActionGroup toolbarActions); } - public static void addConsole(Project project, @Nullable ConsoleFactory consoleFactory, final @NlsContexts.TabTitle String tabTitle, String text) { + public static void addConsole(Project project, + @Nullable ConsoleFactory consoleFactory, + final @NlsContexts.TabTitle String tabTitle, + String text) { addConsole(project, consoleFactory, tabTitle, text, null); } @@ -87,7 +94,14 @@ public final class AnalyzeStacktraceUtil { if (withExecutor) { final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); - RunContentManager.getInstance(project).showRunContent(executor, descriptor); + RunContentManager runContentManager = RunContentManager.getInstance(project); + runContentManager.showRunContent(executor, descriptor); + + for (@NotNull StacktraceTabContentProvider stacktraceRunContentProvider : EP_CONTENT_PROVIDER.getExtensions(project)) { + RunContentDescriptor contentDescriptor = stacktraceRunContentProvider.createRunTabDescriptor(project, text); + if (contentDescriptor == null) continue; + runContentManager.showRunContent(executor, contentDescriptor); + } } consoleView.allowHeavyFilters(); if (consoleFactory == null) { @@ -108,7 +122,8 @@ public final class AnalyzeStacktraceUtil { MyConsolePanel(ExecutionConsole consoleView, ActionGroup toolbarActions) { super(new BorderLayout()); JPanel toolbarPanel = new JPanel(new BorderLayout()); - ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.ANALYZE_STACKTRACE_PANEL_TOOLBAR, toolbarActions, false); + ActionToolbar toolbar = + ActionManager.getInstance().createActionToolbar(ActionPlaces.ANALYZE_STACKTRACE_PANEL_TOOLBAR, toolbarActions, false); toolbar.setTargetComponent(consoleView.getComponent()); toolbarPanel.add(toolbar.getComponent()); add(toolbarPanel, BorderLayout.WEST); diff --git a/platform/lang-impl/src/com/intellij/unscramble/StacktraceTabContentProvider.java b/platform/lang-impl/src/com/intellij/unscramble/StacktraceTabContentProvider.java new file mode 100644 index 000000000000..ac57c1be6d58 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/unscramble/StacktraceTabContentProvider.java @@ -0,0 +1,12 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.unscramble; + +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Experimental +public interface StacktraceTabContentProvider { + @Nullable RunContentDescriptor createRunTabDescriptor(Project project, String text); +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index e7623cc70f3e..aef3600da83e 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -605,6 +605,8 @@ + diff --git a/plugins/devkit/intellij.devkit.stacktrace/resources/intellij.devkit.stacktrace.xml b/plugins/devkit/intellij.devkit.stacktrace/resources/intellij.devkit.stacktrace.xml index 729bd6223fa7..9f15fa485c93 100644 --- a/plugins/devkit/intellij.devkit.stacktrace/resources/intellij.devkit.stacktrace.xml +++ b/plugins/devkit/intellij.devkit.stacktrace/resources/intellij.devkit.stacktrace.xml @@ -8,5 +8,7 @@ + diff --git a/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/FreezeDescriptor.kt b/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/FreezeDescriptor.kt new file mode 100644 index 000000000000..9da68fb79505 --- /dev/null +++ b/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/FreezeDescriptor.kt @@ -0,0 +1,39 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.stacktrace + +import com.intellij.execution.ui.RunContentDescriptor +import com.intellij.openapi.application.EDT +import com.intellij.openapi.project.Project +import com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalyzer +import com.intellij.platform.ide.progress.runWithModalProgressBlocking +import com.intellij.platform.ide.progress.withBackgroundProgress +import com.intellij.unscramble.StacktraceTabContentProvider +import com.intellij.unscramble.AnalyzeStacktraceUtil +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.jetbrains.idea.devkit.DevKitIcons + +object FreezeDescriptor { + suspend fun getFreezeRunDescriptor(text: String, project: Project): RunContentDescriptor? = withContext(Dispatchers.Default) { + withBackgroundProgress(project, DevKitStackTraceBundle.message("progress.title.freeze.analysis")) { + FreezeAnalyzer.analyzeFreeze(text)?.let { result -> + withContext(Dispatchers.EDT) { + AnalyzeStacktraceUtil.addConsole( + project, null, + DevKitStackTraceBundle.message("tab.title.freeze.analyzer"), + "${result.message}\n${result.additionalMessage ?: ""}\n======= Stack Trace: ========= \n${result.threads.joinToString { it -> it.stackTrace }}", + DevKitIcons.Freeze, false + ) + } + } + } + } +} + +class FreezeTabContentProvider : StacktraceTabContentProvider { + override fun createRunTabDescriptor(project: Project, text: String): RunContentDescriptor? { + return runWithModalProgressBlocking(project, DevKitStackTraceBundle.message("progress.title.freeze.analysis")) { + FreezeDescriptor.getFreezeRunDescriptor(text, project) + } + } +} \ No newline at end of file diff --git a/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/editor/StackTraceFileEditor.kt b/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/editor/StackTraceFileEditor.kt index 670e67d4d1e2..033ee801780e 100644 --- a/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/editor/StackTraceFileEditor.kt +++ b/plugins/devkit/intellij.devkit.stacktrace/src/org/jetbrains/idea/devkit/stacktrace/editor/StackTraceFileEditor.kt @@ -14,14 +14,12 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.UserDataHolderBase import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.wm.ToolWindow -import com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalyzer import com.intellij.platform.ide.progress.withBackgroundProgress import com.intellij.threadDumpParser.ThreadDumpParser.parse import com.intellij.ui.content.Content import com.intellij.ui.content.ContentFactory.getInstance import com.intellij.ui.content.ContentManager import com.intellij.ui.content.TabbedPaneContentUI -import com.intellij.unscramble.AnalyzeStacktraceUtil import com.intellij.unscramble.UnscrambleUtils.addConsole import com.intellij.util.concurrency.annotations.RequiresEdt import kotlinx.coroutines.* @@ -30,8 +28,8 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce -import org.jetbrains.idea.devkit.DevKitIcons import org.jetbrains.idea.devkit.stacktrace.DevKitStackTraceBundle +import org.jetbrains.idea.devkit.stacktrace.FreezeDescriptor import org.jetbrains.idea.devkit.stacktrace.util.StackTracePluginScope import java.awt.BorderLayout import java.beans.PropertyChangeListener @@ -120,17 +118,7 @@ class StackTraceFileEditor(private val project: Project, private val file: Virtu } private suspend fun addFreezeAnalysisContent(contentManager: ContentManager) { - withContext(Dispatchers.Default) { - withBackgroundProgress(project, DevKitStackTraceBundle.message("progress.title.freeze.analysis")) { - FreezeAnalyzer.analyzeFreeze(document.text) - } - }?.let { result -> - val freezeDescriptor = AnalyzeStacktraceUtil.addConsole( - project, null, - DevKitStackTraceBundle.message("tab.title.freeze.analyzer"), - "${result.message}\n${result.additionalMessage ?: ""}\n======= Stack Trace: ========= \n${result.threads.joinToString { it -> it.stackTrace }}", - DevKitIcons.Freeze, false - ) + FreezeDescriptor.getFreezeRunDescriptor(document.text, project)?.let { freezeDescriptor -> contentManager.addContent(createNewContent(freezeDescriptor).apply { executionId = freezeDescriptor.executionId component = freezeDescriptor.component