Disable "Decompile" button if bytecode generation threw exception

#KT-13791 Fixed
This commit is contained in:
Dmitry Jemerov
2018-01-12 18:45:34 +01:00
parent 404f9cc7d8
commit e46f69bb36
2 changed files with 48 additions and 45 deletions
@@ -48,6 +48,11 @@ import javax.swing.JButton
import javax.swing.JCheckBox import javax.swing.JCheckBox
import javax.swing.JPanel import javax.swing.JPanel
sealed class BytecodeGenerationResult {
data class Bytecode(val text: String) : BytecodeGenerationResult()
data class Error(val text: String) : BytecodeGenerationResult()
}
class KotlinBytecodeToolWindow(private val myProject: Project, private val toolWindow: ToolWindow) : JPanel(BorderLayout()), Disposable { class KotlinBytecodeToolWindow(private val myProject: Project, private val toolWindow: ToolWindow) : JPanel(BorderLayout()), Disposable {
private val LOG = Logger.getInstance(KotlinBytecodeToolWindow::class.java) private val LOG = Logger.getInstance(KotlinBytecodeToolWindow::class.java)
@@ -59,7 +64,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
private val jvm8Target: JCheckBox private val jvm8Target: JCheckBox
private val ir: JCheckBox private val ir: JCheckBox
private inner class UpdateBytecodeToolWindowTask : LongRunningReadTask<Location, String>() { private inner class UpdateBytecodeToolWindowTask : LongRunningReadTask<Location, BytecodeGenerationResult>() {
override fun prepareRequestInfo(): Location? { override fun prepareRequestInfo(): Location? {
if (!toolWindow.isVisible) { if (!toolWindow.isVisible) {
return null return null
@@ -87,7 +92,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
setText(DEFAULT_TEXT) setText(DEFAULT_TEXT)
} }
override fun processRequest(location: Location): String { override fun processRequest(location: Location): BytecodeGenerationResult {
val ktFile = location.kFile!! val ktFile = location.kFile!!
val configuration = CompilerConfiguration() val configuration = CompilerConfiguration()
@@ -115,39 +120,48 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
return getBytecodeForFile(ktFile, configuration) return getBytecodeForFile(ktFile, configuration)
} }
override fun onResultReady(requestInfo: Location, resultText: String?) { override fun onResultReady(requestInfo: Location, result: BytecodeGenerationResult?) {
val editor = requestInfo.getEditor()!! val editor = requestInfo.getEditor()!!
if (resultText == null) { if (result == null) {
return return
} }
setText(resultText) when (result) {
is BytecodeGenerationResult.Error -> {
decompile.isEnabled = false
setText(result.text)
}
is BytecodeGenerationResult.Bytecode -> {
decompile.isEnabled = true
setText(result.text)
val fileStartOffset = requestInfo.getStartOffset() val fileStartOffset = requestInfo.getStartOffset()
val fileEndOffset = requestInfo.getEndOffset() val fileEndOffset = requestInfo.getEndOffset()
val document = editor.document val document = editor.document
val startLine = document.getLineNumber(fileStartOffset) val startLine = document.getLineNumber(fileStartOffset)
var endLine = document.getLineNumber(fileEndOffset) var endLine = document.getLineNumber(fileEndOffset)
if (endLine > startLine && fileEndOffset > 0 && document.charsSequence[fileEndOffset - 1] == '\n') { if (endLine > startLine && fileEndOffset > 0 && document.charsSequence[fileEndOffset - 1] == '\n') {
endLine-- endLine--
}
val byteCodeDocument = myEditor.document
val linesRange = mapLines(byteCodeDocument.text, startLine, endLine)
val endSelectionLineIndex = Math.min(linesRange.second + 1, byteCodeDocument.lineCount)
val startOffset = byteCodeDocument.getLineStartOffset(linesRange.first)
val endOffset = Math.min(byteCodeDocument.getLineStartOffset(endSelectionLineIndex), byteCodeDocument.textLength)
myEditor.caretModel.moveToOffset(endOffset)
myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.caretModel.moveToOffset(startOffset)
myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.selectionModel.setSelection(startOffset, endOffset)
}
} }
val byteCodeDocument = myEditor.document
val linesRange = mapLines(byteCodeDocument.text, startLine, endLine)
val endSelectionLineIndex = Math.min(linesRange.second + 1, byteCodeDocument.lineCount)
val startOffset = byteCodeDocument.getLineStartOffset(linesRange.first)
val endOffset = Math.min(byteCodeDocument.getLineStartOffset(endSelectionLineIndex), byteCodeDocument.textLength)
myEditor.caretModel.moveToOffset(endOffset)
myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.caretModel.moveToOffset(startOffset)
myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.selectionModel.setSelection(startOffset, endOffset)
} }
} }
@@ -217,14 +231,14 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
"*/" "*/"
// public for tests // public for tests
fun getBytecodeForFile(ktFile: KtFile, configuration: CompilerConfiguration): String { fun getBytecodeForFile(ktFile: KtFile, configuration: CompilerConfiguration): BytecodeGenerationResult {
val state: GenerationState val state: GenerationState
try { try {
state = compileSingleFile(ktFile, configuration) state = compileSingleFile(ktFile, configuration)
} catch (e: ProcessCanceledException) { } catch (e: ProcessCanceledException) {
throw e throw e
} catch (e: Exception) { } catch (e: Exception) {
return printStackTraceToString(e) return BytecodeGenerationResult.Error(printStackTraceToString(e))
} }
val answer = StringBuilder() val answer = StringBuilder()
@@ -252,7 +266,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
answer.append(outputFile.asText()).append("\n\n") answer.append(outputFile.asText()).append("\n\n")
} }
return answer.toString() return BytecodeGenerationResult.Bytecode(answer.toString())
} }
fun compileSingleFile( fun compileSingleFile(
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * 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/LICENSE.txt file.
* 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.internal package org.jetbrains.kotlin.idea.internal
@@ -51,8 +40,8 @@ abstract class AbstractBytecodeToolWindowTest: KotlinLightCodeInsightFixtureTest
} }
val bytecodes = KotlinBytecodeToolWindow.getBytecodeForFile(file, configuration) val bytecodes = KotlinBytecodeToolWindow.getBytecodeForFile(file, configuration)
assert(bytecodes.contains("// ================")) { assert(bytecodes is BytecodeGenerationResult.Bytecode) {
"The header \"// ================\" is missing.\n This means that there is an exception failed during compilation:\n$bytecodes" "Exception failed during compilation:\n$bytecodes"
} }
} }
} }