diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java index 3790044e0518..fb09065e45de 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection.bytecodeAnalysis; import com.intellij.codeInsight.*; @@ -34,12 +34,12 @@ import com.intellij.testFramework.fixtures.MavenDependencyUtil; import one.util.streamex.EntryStream; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.java.decompiler.IdeaDecompiler; import java.util.*; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; +import static org.jetbrains.java.decompiler.IdeaDecompilerKt.IDEA_DECOMPILER_BANNER; public class BytecodeAnalysisIntegrationTest extends LightJavaCodeInsightFixtureTestCase { private static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = JavaMethodContractUtil.ORG_JETBRAINS_ANNOTATIONS_CONTRACT; @@ -122,7 +122,7 @@ public class BytecodeAnalysisIntegrationTest extends LightJavaCodeInsightFixture assertNotNull(psiClass); myFixture.openFileInEditor(psiClass.getContainingFile().getVirtualFile()); String documentText = myFixture.getEditor().getDocument().getText(); - assertThat(documentText).startsWith(IdeaDecompiler.BANNER); + assertThat(documentText).startsWith(IDEA_DECOMPILER_BANNER); Set gutters = myFixture.findAllGutters().stream() .map(GutterMark::getTooltipText) .filter(Objects::nonNull) diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt index a2ff80bfc362..8dcd2d0ad418 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.java.decompiler import com.intellij.application.options.CodeStyle @@ -39,81 +39,55 @@ import java.util.concurrent.Callable import java.util.concurrent.Future import java.util.jar.Manifest +const val IDEA_DECOMPILER_BANNER: String = "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\n" + class IdeaDecompiler : ClassFileDecompilers.Light() { - companion object { - const val BANNER: String = "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\n" - - private const val LEGAL_NOTICE_KEY = "decompiler.legal.notice.accepted" - - private const val POSTPONE_EXIT_CODE = DialogWrapper.CANCEL_EXIT_CODE - private const val DECLINE_EXIT_CODE = DialogWrapper.NEXT_USER_EXIT_CODE - - private val TASK_KEY: Key> = Key.create("java.decompiler.optimistic.task") - - private fun getOptions(): Map { - val options = CodeStyle.getDefaultSettings().getIndentOptions(JavaFileType.INSTANCE) - val indent = StringUtil.repeat(" ", options.INDENT_SIZE) - return mapOf( - IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR to "0", - IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1", - IFernflowerPreferences.REMOVE_SYNTHETIC to "1", - IFernflowerPreferences.REMOVE_BRIDGE to "1", - IFernflowerPreferences.NEW_LINE_SEPARATOR to "1", - IFernflowerPreferences.BANNER to BANNER, - IFernflowerPreferences.MAX_PROCESSING_METHOD to 60, - IFernflowerPreferences.INDENT_STRING to indent, - IFernflowerPreferences.IGNORE_INVALID_BYTECODE to "1", - IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES to "1", - //IFernflowerPreferences.UNIT_TEST_MODE to if (ApplicationManager.getApplication().isUnitTestMode) "1" else "0" - ) - } - - private fun canWork(): Boolean = - ApplicationManager.getApplication().isUnitTestMode || PropertiesComponent.getInstance().isValueSet(LEGAL_NOTICE_KEY) - } - class LegalBurden : FileEditorManagerListener.Before { - private var myShowNotice = !canWork() + private var showNotice = !canWork() override fun beforeFileOpened(source: FileEditorManager, file: VirtualFile) { - if (myShowNotice && file.fileType === JavaClassFileType.INSTANCE) { - val decompiler = ClassFileDecompilers.getInstance().find(file, ClassFileDecompilers.Light::class.java) - if (decompiler is IdeaDecompiler) { - TASK_KEY.set(file, ApplicationManager.getApplication().executeOnPooledThread(Callable { decompiler.decompile(file) })) + if (!showNotice || file.fileType !== JavaClassFileType.INSTANCE) { + return + } - val title = IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.path, 40, true)) - val message = IdeaDecompilerBundle.message("legal.notice.text") - val result = LegalNoticeDialog.build(title, message) - .withCancelText(IdeaDecompilerBundle.message("legal.notice.action.postpone")) - .withCustomAction(IdeaDecompilerBundle.message("legal.notice.action.reject"), DECLINE_EXIT_CODE) - .show() - when (result) { - DialogWrapper.OK_EXIT_CODE -> { - myShowNotice = false - PropertiesComponent.getInstance().setValue(LEGAL_NOTICE_KEY, true) - ApplicationManager.getApplication().invokeLater { FileContentUtilCore.reparseFiles(file) } - } + val decompiler = ClassFileDecompilers.getInstance().find(file, ClassFileDecompilers.Light::class.java) + if (decompiler !is IdeaDecompiler) { + return + } - DECLINE_EXIT_CODE -> { - myShowNotice = false - TASK_KEY.set(file, null) + TASK_KEY.set(file, ApplicationManager.getApplication().executeOnPooledThread(Callable { decompiler.decompile(file) })) - val id = PluginId.getId("org.jetbrains.java.decompiler") - PluginManagerCore.disablePlugin(id) + val title = IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.path, 40, true)) + val message = IdeaDecompilerBundle.message("legal.notice.text") + val result = LegalNoticeDialog.build(title, message) + .withCancelText(IdeaDecompilerBundle.message("legal.notice.action.postpone")) + .withCustomAction(IdeaDecompilerBundle.message("legal.notice.action.reject"), DECLINE_EXIT_CODE) + .show() + when (result) { + DialogWrapper.OK_EXIT_CODE -> { + showNotice = false + PropertiesComponent.getInstance().setValue(LEGAL_NOTICE_KEY, true) + ApplicationManager.getApplication().invokeLater { FileContentUtilCore.reparseFiles(file) } + } - val plugin = PluginManagerCore.getPlugin(id) - if (plugin is IdeaPluginDescriptorImpl && DynamicPlugins.allowLoadUnloadWithoutRestart(plugin)) { - ApplicationManager.getApplication().invokeLater { - DynamicPlugins.unloadPlugin(plugin, DynamicPlugins.UnloadPluginOptions(save = false)) - } - } - } + DECLINE_EXIT_CODE -> { + showNotice = false + TASK_KEY.set(file, null) - POSTPONE_EXIT_CODE -> { - TASK_KEY.set(file, null) + val id = PluginId.getId("org.jetbrains.java.decompiler") + PluginManagerCore.disablePlugin(id) + + val plugin = PluginManagerCore.getPlugin(id) + if (plugin is IdeaPluginDescriptorImpl && DynamicPlugins.allowLoadUnloadWithoutRestart(plugin)) { + ApplicationManager.getApplication().invokeLater { + DynamicPlugins.unloadPlugin(plugin, DynamicPlugins.UnloadPluginOptions(save = false)) } } } + + POSTPONE_EXIT_CODE -> { + TASK_KEY.set(file, null) + } } } } @@ -174,12 +148,12 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { throw e } - val mapping = saver.myMapping + val mapping = saver.mapping if (mapping != null) { file.putUserData(LineNumbersMapping.LINE_NUMBERS_MAPPING_KEY, LineNumbersMapping.ArrayBasedMapping(mapping)) } - return saver.myResult + return saver.result } catch (e: ProcessCanceledException) { throw e @@ -204,13 +178,13 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { } private class MyResultSaver : IResultSaver { - var myResult = "" - var myMapping: IntArray? = null + var result = "" + var mapping: IntArray? = null override fun saveClassFile(path: String, qualifiedName: String, entryName: String, content: String, mapping: IntArray?) { - if (myResult.isEmpty()) { - myResult = content - myMapping = mapping + if (result.isEmpty()) { + result = content + this.mapping = mapping } } @@ -235,3 +209,32 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { return value } } + +private const val LEGAL_NOTICE_KEY = "decompiler.legal.notice.accepted" + +private const val POSTPONE_EXIT_CODE = DialogWrapper.CANCEL_EXIT_CODE +private const val DECLINE_EXIT_CODE = DialogWrapper.NEXT_USER_EXIT_CODE + +private val TASK_KEY: Key> = Key.create("java.decompiler.optimistic.task") + +private fun getOptions(): Map { + val options = CodeStyle.getDefaultSettings().getIndentOptions(JavaFileType.INSTANCE) + val indent = " ".repeat(options.INDENT_SIZE) + return mapOf( + IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR to "0", + IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1", + IFernflowerPreferences.REMOVE_SYNTHETIC to "1", + IFernflowerPreferences.REMOVE_BRIDGE to "1", + IFernflowerPreferences.NEW_LINE_SEPARATOR to "1", + IFernflowerPreferences.BANNER to IDEA_DECOMPILER_BANNER, + IFernflowerPreferences.MAX_PROCESSING_METHOD to 60, + IFernflowerPreferences.INDENT_STRING to indent, + IFernflowerPreferences.IGNORE_INVALID_BYTECODE to "1", + IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES to "1", + //IFernflowerPreferences.UNIT_TEST_MODE to if (ApplicationManager.getApplication().isUnitTestMode) "1" else "0" + ) +} + +private fun canWork(): Boolean { + return ApplicationManager.getApplication().isUnitTestMode || PropertiesComponent.getInstance().isValueSet(LEGAL_NOTICE_KEY) +} \ No newline at end of file diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt index 6f52f51d9250..cbb40ece1421 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.java.decompiler import com.intellij.JavaTestUtil @@ -55,7 +55,7 @@ class IdeaDecompilerTest : LightJavaCodeInsightFixtureTestCase() { fun testSimple() { val file = getTestFile("${IdeaTestUtil.getMockJdk18Path().path}/jre/lib/rt.jar!/java/lang/String.class") val decompiled = IdeaDecompiler().getText(file).toString() - assertTrue(decompiled, decompiled.startsWith("${IdeaDecompiler.BANNER}package java.lang;\n")) + assertTrue(decompiled, decompiled.startsWith("${IDEA_DECOMPILER_BANNER}package java.lang;\n")) assertTrue(decompiled, decompiled.contains("public final class String")) assertTrue(decompiled, decompiled.contains("@deprecated")) assertTrue(decompiled, decompiled.contains("private static class CaseInsensitiveComparator")) @@ -222,7 +222,7 @@ class IdeaDecompilerTest : LightJavaCodeInsightFixtureTestCase() { } val decompiled = psiFile.mirror.text - assertTrue(file.path, decompiled.startsWith(IdeaDecompiler.BANNER) || file.name.endsWith("-info.class")) + assertTrue(file.path, decompiled.startsWith(IDEA_DECOMPILER_BANNER) || file.name.endsWith("-info.class")) // check that no mapped line number is on an empty line val prefix = "// " diff --git a/plugins/performanceTesting/src/com/jetbrains/performancePlugin/commands/AcceptDecompileNotice.kt b/plugins/performanceTesting/src/com/jetbrains/performancePlugin/commands/AcceptDecompileNotice.kt index 957890519104..1299014fdcde 100644 --- a/plugins/performanceTesting/src/com/jetbrains/performancePlugin/commands/AcceptDecompileNotice.kt +++ b/plugins/performanceTesting/src/com/jetbrains/performancePlugin/commands/AcceptDecompileNotice.kt @@ -1,15 +1,16 @@ package com.jetbrains.performancePlugin.commands import com.intellij.ide.util.PropertiesComponent +import com.intellij.openapi.components.serviceAsync import com.intellij.openapi.ui.playback.PlaybackContext import com.intellij.openapi.ui.playback.commands.PlaybackCommandCoroutineAdapter import org.jetbrains.annotations.NonNls -class AcceptDecompileNotice(text: String, line: Int): PlaybackCommandCoroutineAdapter(text, line) { +internal class AcceptDecompileNotice(text: String, line: Int): PlaybackCommandCoroutineAdapter(text, line) { companion object { const val PREFIX: @NonNls String = CMD_PREFIX + "acceptDecompileNotice" } override suspend fun doExecute(context: PlaybackContext) { - PropertiesComponent.getInstance().setValue("decompiler.legal.notice.accepted", true) + serviceAsync().setValue("decompiler.legal.notice.accepted", true) } } \ No newline at end of file