KotlinBytecodeToolWindow: convert to .kt

This commit is contained in:
Dmitry Jemerov
2018-01-12 18:36:14 +01:00
parent bad76eb5c2
commit 404f9cc7d8
@@ -1,419 +1,367 @@
/* /*
* 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
import com.intellij.ide.highlighter.JavaFileType; import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.ScrollType
import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project
import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable
import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindow; import com.intellij.util.Alarm
import com.intellij.util.Alarm; import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection; import org.jetbrains.kotlin.codegen.DefaultCodegenFactory
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory; import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.ClassBuilderFactories; import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.CompilationErrorHandler; import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.codegen.DefaultCodegenFactory; import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade; import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
import org.jetbrains.kotlin.config.*; import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.idea.util.InfinitePeriodicalTask
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.kotlin.idea.util.LongRunningReadTask
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils; import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.idea.project.PlatformKt; import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.idea.util.InfinitePeriodicalTask; import org.jetbrains.kotlin.utils.join
import org.jetbrains.kotlin.idea.util.LongRunningReadTask; import java.awt.BorderLayout
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil; import java.awt.FlowLayout
import org.jetbrains.kotlin.psi.KtClassOrObject; import java.io.PrintWriter
import org.jetbrains.kotlin.psi.KtFile; import java.io.StringWriter
import org.jetbrains.kotlin.psi.KtScript; import java.util.*
import org.jetbrains.kotlin.resolve.BindingContext; import javax.swing.JButton
import org.jetbrains.kotlin.utils.StringsKt; import javax.swing.JCheckBox
import javax.swing.JPanel
import javax.swing.*; class KotlinBytecodeToolWindow(private val myProject: Project, private val toolWindow: ToolWindow) : JPanel(BorderLayout()), Disposable {
import java.awt.*; private val LOG = Logger.getInstance(KotlinBytecodeToolWindow::class.java)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import java.util.List;
public class KotlinBytecodeToolWindow extends JPanel implements Disposable { private val myEditor: Editor
private final Logger LOG = Logger.getInstance(KotlinBytecodeToolWindow.class); private val enableInline: JCheckBox
private val enableOptimization: JCheckBox
private val enableAssertions: JCheckBox
private val decompile: JButton
private val jvm8Target: JCheckBox
private val ir: JCheckBox
private static final int UPDATE_DELAY = 1000; private inner class UpdateBytecodeToolWindowTask : LongRunningReadTask<Location, String>() {
private static final String DEFAULT_TEXT = "/*\n" + override fun prepareRequestInfo(): Location? {
"Generated bytecode for Kotlin source file.\n" + if (!toolWindow.isVisible) {
"No Kotlin source file is opened.\n" + return null
"*/";
private class UpdateBytecodeToolWindowTask extends LongRunningReadTask<Location, String> {
@Override
protected Location prepareRequestInfo() {
if (!toolWindow.isVisible()) {
return null;
} }
Location location = Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor(), myProject); val location = Location.fromEditor(FileEditorManager.getInstance(myProject).selectedTextEditor, myProject)
if (location.getEditor() == null) { if (location.getEditor() == null) {
return null; return null
} }
KtFile file = location.getKFile(); val file = location.kFile
if (file == null || !ProjectRootsUtil.isInProjectSource(file)) { return if (file == null || !ProjectRootsUtil.isInProjectSource(file)) {
return null; null
} } else location
return location;
} }
@NotNull override fun cloneRequestInfo(location: Location): Location {
@Override val newLocation = super.cloneRequestInfo(location)
protected Location cloneRequestInfo(@NotNull Location location) { assert(location == newLocation) { "cloneRequestInfo should generate same location object" }
Location newLocation = super.cloneRequestInfo(location); return newLocation
assert location.equals(newLocation) : "cloneRequestInfo should generate same location object";
return newLocation;
} }
@Override override fun hideResultOnInvalidLocation() {
protected void hideResultOnInvalidLocation() { setText(DEFAULT_TEXT)
setText(DEFAULT_TEXT);
} }
@NotNull override fun processRequest(location: Location): String {
@Override val ktFile = location.kFile!!
protected String processRequest(@NotNull Location location) {
KtFile ktFile = location.getKFile();
assert ktFile != null;
CompilerConfiguration configuration = new CompilerConfiguration(); val configuration = CompilerConfiguration()
if (!enableInline.isSelected()) { if (!enableInline.isSelected) {
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true); configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true)
} }
if (!enableAssertions.isSelected()) { if (!enableAssertions.isSelected) {
configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, true); configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, true)
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, true); configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, true)
} }
if (!enableOptimization.isSelected()) { if (!enableOptimization.isSelected) {
configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, true); configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, true)
} }
if (jvm8Target.isSelected()) { if (jvm8Target.isSelected) {
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8); configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
} }
if (ir.isSelected()) { if (ir.isSelected) {
configuration.put(JVMConfigurationKeys.IR, true); configuration.put(JVMConfigurationKeys.IR, true)
} }
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, PlatformKt.getLanguageVersionSettings(ktFile)); configuration.languageVersionSettings = ktFile.languageVersionSettings
return getBytecodeForFile(ktFile, configuration); return getBytecodeForFile(ktFile, configuration)
} }
@Override override fun onResultReady(requestInfo: Location, resultText: String?) {
protected void onResultReady(@NotNull Location requestInfo, String resultText) { val editor = requestInfo.getEditor()!!
Editor editor = requestInfo.getEditor();
assert editor != null;
if (resultText == null) { if (resultText == null) {
return; return
} }
setText(resultText); setText(resultText)
int fileStartOffset = requestInfo.getStartOffset(); val fileStartOffset = requestInfo.getStartOffset()
int fileEndOffset = requestInfo.getEndOffset(); val fileEndOffset = requestInfo.getEndOffset()
Document document = editor.getDocument(); val document = editor.document
int startLine = document.getLineNumber(fileStartOffset); val startLine = document.getLineNumber(fileStartOffset)
int endLine = document.getLineNumber(fileEndOffset); var endLine = document.getLineNumber(fileEndOffset)
if (endLine > startLine && fileEndOffset > 0 && document.getCharsSequence().charAt(fileEndOffset - 1) == '\n') { if (endLine > startLine && fileEndOffset > 0 && document.charsSequence[fileEndOffset - 1] == '\n') {
endLine--; endLine--
} }
Document byteCodeDocument = myEditor.getDocument(); val byteCodeDocument = myEditor.document
Pair<Integer, Integer> linesRange = mapLines(byteCodeDocument.getText(), startLine, endLine); val linesRange = mapLines(byteCodeDocument.text, startLine, endLine)
int endSelectionLineIndex = Math.min(linesRange.second + 1, byteCodeDocument.getLineCount()); val endSelectionLineIndex = Math.min(linesRange.second + 1, byteCodeDocument.lineCount)
int startOffset = byteCodeDocument.getLineStartOffset(linesRange.first); val startOffset = byteCodeDocument.getLineStartOffset(linesRange.first)
int endOffset = Math.min(byteCodeDocument.getLineStartOffset(endSelectionLineIndex), byteCodeDocument.getTextLength()); val endOffset = Math.min(byteCodeDocument.getLineStartOffset(endSelectionLineIndex), byteCodeDocument.textLength)
myEditor.getCaretModel().moveToOffset(endOffset); myEditor.caretModel.moveToOffset(endOffset)
myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.getCaretModel().moveToOffset(startOffset); myEditor.caretModel.moveToOffset(startOffset)
myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); myEditor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
myEditor.getSelectionModel().setSelection(startOffset, endOffset); myEditor.selectionModel.setSelection(startOffset, endOffset)
} }
} }
private final Editor myEditor; init {
private final Project myProject;
private final ToolWindow toolWindow;
private final JCheckBox enableInline;
private final JCheckBox enableOptimization;
private final JCheckBox enableAssertions;
private final JButton decompile;
private final JCheckBox jvm8Target;
private final JCheckBox ir;
public KotlinBytecodeToolWindow(Project project, ToolWindow toolWindow) {
super(new BorderLayout());
myProject = project;
this.toolWindow = toolWindow;
myEditor = EditorFactory.getInstance().createEditor( myEditor = EditorFactory.getInstance().createEditor(
EditorFactory.getInstance().createDocument(""), project, JavaFileType.INSTANCE, true); EditorFactory.getInstance().createDocument(""), myProject, JavaFileType.INSTANCE, true
add(myEditor.getComponent()); )
add(myEditor.component)
JPanel optionPanel = new JPanel(new FlowLayout()); val optionPanel = JPanel(FlowLayout())
add(optionPanel, BorderLayout.NORTH); add(optionPanel, BorderLayout.NORTH)
decompile = new JButton("Decompile"); decompile = JButton("Decompile")
if (KotlinDecompilerService.Companion.getInstance() != null) { if (KotlinDecompilerService.getInstance() != null) {
optionPanel.add(decompile); optionPanel.add(decompile)
decompile.addActionListener(new ActionListener() { decompile.addActionListener {
@Override val location = Location.fromEditor(FileEditorManager.getInstance(myProject).selectedTextEditor, myProject)
public void actionPerformed(ActionEvent e) { val file = location.kFile
Location location = Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor(), myProject); if (file != null) {
KtFile file = location.getKFile(); try {
if (file != null) { showDecompiledCode(file)
try { } catch (ex: DecompileFailedException) {
KotlinDecompilerAdapterKt.showDecompiledCode(file); LOG.info(ex)
} Messages.showErrorDialog(myProject, "Failed to decompile " + file.name + ": " + ex, "Kotlin Bytecode Decompiler")
catch (DecompileFailedException ex) {
LOG.info(ex);
Messages.showErrorDialog(myProject, "Failed to decompile " + file.getName() + ": " + ex, "Kotlin Bytecode Decompiler");
}
} }
} }
}); }
} }
/*TODO: try to extract default parameter from compiler options*/ /*TODO: try to extract default parameter from compiler options*/
enableInline = new JCheckBox("Inline", true); enableInline = JCheckBox("Inline", true)
enableOptimization = new JCheckBox("Optimization", true); enableOptimization = JCheckBox("Optimization", true)
enableAssertions = new JCheckBox("Assertions", true); enableAssertions = JCheckBox("Assertions", true)
jvm8Target = new JCheckBox("JVM 8 target", false); jvm8Target = JCheckBox("JVM 8 target", false)
ir = new JCheckBox("IR", false); ir = JCheckBox("IR", false)
optionPanel.add(enableInline); optionPanel.add(enableInline)
optionPanel.add(enableOptimization); optionPanel.add(enableOptimization)
optionPanel.add(enableAssertions); optionPanel.add(enableAssertions)
optionPanel.add(ir); optionPanel.add(ir)
optionPanel.add(jvm8Target); optionPanel.add(jvm8Target)
new InfinitePeriodicalTask(UPDATE_DELAY, Alarm.ThreadToUse.SWING_THREAD, this, new Computable<LongRunningReadTask>() { InfinitePeriodicalTask(
@Override UPDATE_DELAY.toLong(),
public LongRunningReadTask compute() { Alarm.ThreadToUse.SWING_THREAD,
return new UpdateBytecodeToolWindowTask(); this,
} Computable<LongRunningReadTask<*, *>> { UpdateBytecodeToolWindowTask() }).start()
}).start();
setText(DEFAULT_TEXT); setText(DEFAULT_TEXT)
} }
// public for tests private fun setText(resultText: String) {
@NotNull ApplicationManager.getApplication().runWriteAction { myEditor.document.setText(StringUtil.convertLineSeparators(resultText)) }
public static String getBytecodeForFile(@NotNull KtFile ktFile, @NotNull CompilerConfiguration configuration) { }
GenerationState state;
try {
state = compileSingleFile(ktFile, configuration);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
return printStackTraceToString(e);
}
StringBuilder answer = new StringBuilder(); override fun dispose() {
EditorFactory.getInstance().releaseEditor(myEditor)
}
Collection<Diagnostic> diagnostics = state.getCollectedExtraJvmDiagnostics().all(); companion object {
if (!diagnostics.isEmpty()) {
answer.append("// Backend Errors: \n"); private val UPDATE_DELAY = 1000
answer.append("// ================\n"); private val DEFAULT_TEXT = "/*\n" +
for (Diagnostic diagnostic : diagnostics) { "Generated bytecode for Kotlin source file.\n" +
answer.append("// Error at ") "No Kotlin source file is opened.\n" +
.append(diagnostic.getPsiFile().getName()) "*/"
.append(StringsKt.join(diagnostic.getTextRanges(), ","))
// public for tests
fun getBytecodeForFile(ktFile: KtFile, configuration: CompilerConfiguration): String {
val state: GenerationState
try {
state = compileSingleFile(ktFile, configuration)
} catch (e: ProcessCanceledException) {
throw e
} catch (e: Exception) {
return printStackTraceToString(e)
}
val answer = StringBuilder()
val diagnostics = state.collectedExtraJvmDiagnostics.all()
if (!diagnostics.isEmpty()) {
answer.append("// Backend Errors: \n")
answer.append("// ================\n")
for (diagnostic in diagnostics) {
answer.append("// Error at ")
.append(diagnostic.psiFile.name)
.append(join(diagnostic.textRanges, ","))
.append(": ") .append(": ")
.append(DefaultErrorMessages.render(diagnostic)) .append(DefaultErrorMessages.render(diagnostic))
.append("\n"); .append("\n")
}
answer.append("// ================\n\n")
} }
answer.append("// ================\n\n");
val outputFiles = state.factory
for (outputFile in outputFiles.asList()) {
answer.append("// ================")
answer.append(outputFile.relativePath)
answer.append(" =================\n")
answer.append(outputFile.asText()).append("\n\n")
}
return answer.toString()
} }
OutputFileCollection outputFiles = state.getFactory(); fun compileSingleFile(
for (OutputFile outputFile : outputFiles.asList()) { ktFile: KtFile,
answer.append("// ================"); configuration: CompilerConfiguration
answer.append(outputFile.getRelativePath()); ): GenerationState {
answer.append(" =================\n"); val resolutionFacade = ktFile.getResolutionFacade()
answer.append(outputFile.asText()).append("\n\n");
}
return answer.toString(); val bindingContextForFile = resolutionFacade.analyzeFullyAndGetResult(listOf(ktFile)).bindingContext
}
@NotNull val (bindingContext, toProcess) = DebuggerUtils.analyzeInlinedFunctions(
public static GenerationState compileSingleFile(
@NotNull final KtFile ktFile,
@NotNull CompilerConfiguration configuration
) {
ResolutionFacade resolutionFacade = ResolutionUtils.getResolutionFacade(ktFile);
BindingContext bindingContextForFile = resolutionFacade.analyzeFullyAndGetResult(Collections.singletonList(ktFile)).getBindingContext();
kotlin.Pair<BindingContext, List<KtFile>> result = DebuggerUtils.INSTANCE.analyzeInlinedFunctions(
resolutionFacade, ktFile, configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE), resolutionFacade, ktFile, configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE),
bindingContextForFile bindingContextForFile
); )
BindingContext bindingContext = result.getFirst(); val generateClassFilter = object : GenerationState.GenerateClassFilter() {
List<KtFile> toProcess = result.getSecond(); override fun shouldGeneratePackagePart(file: KtFile): Boolean {
return file === ktFile
}
GenerationState.GenerateClassFilter generateClassFilter = new GenerationState.GenerateClassFilter() { override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean {
@Override return true
public boolean shouldGeneratePackagePart(@NotNull KtFile file) { }
return file == ktFile;
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean {
return processingClassOrObject.containingKtFile === ktFile
}
override fun shouldGenerateScript(script: KtScript): Boolean {
return script.containingKtFile === ktFile
}
} }
@Override val state = GenerationState.Builder(
public boolean shouldAnnotateClass(@NotNull KtClassOrObject processingClassOrObject) { ktFile.project, ClassBuilderFactories.TEST, resolutionFacade.moduleDescriptor, bindingContext, toProcess,
return true;
}
@Override
public boolean shouldGenerateClass(@NotNull KtClassOrObject processingClassOrObject) {
return processingClassOrObject.getContainingKtFile() == ktFile;
}
@Override
public boolean shouldGenerateScript(@NotNull KtScript script) {
return script.getContainingKtFile() == ktFile;
}
};
GenerationState state = new GenerationState.Builder(
ktFile.getProject(), ClassBuilderFactories.TEST, resolutionFacade.getModuleDescriptor(), bindingContext, toProcess,
configuration configuration
) )
.generateDeclaredClassFilter(generateClassFilter) .generateDeclaredClassFilter(generateClassFilter)
.codegenFactory(configuration.getBoolean(JVMConfigurationKeys.IR) .codegenFactory(
? JvmIrCodegenFactory.INSTANCE if (configuration.getBoolean(JVMConfigurationKeys.IR))
: DefaultCodegenFactory.INSTANCE) JvmIrCodegenFactory
.build(); else
DefaultCodegenFactory
)
.build()
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION)
return state; return state
}
private static Pair<Integer, Integer> mapLines(String text, int startLine, int endLine) {
int byteCodeLine = 0;
int byteCodeStartLine = -1;
int byteCodeEndLine = -1;
List<Integer> lines = new ArrayList<Integer>();
for (String line : text.split("\n")) {
line = line.trim();
if (line.startsWith("LINENUMBER")) {
int ktLineNum = new Scanner(line.substring("LINENUMBER".length())).nextInt() - 1;
lines.add(ktLineNum);
}
}
Collections.sort(lines);
for (Integer line : lines) {
if (line >= startLine) {
startLine = line;
break;
}
} }
for (String line : text.split("\n")) { private fun mapLines(text: String, startLine: Int, endLine: Int): Pair<Int, Int> {
line = line.trim(); var startLine = startLine
var byteCodeLine = 0
var byteCodeStartLine = -1
var byteCodeEndLine = -1
if (line.startsWith("LINENUMBER")) { val lines = ArrayList<Int>()
int ktLineNum = new Scanner(line.substring("LINENUMBER".length())).nextInt() - 1; for (line in text.split("\n").dropLastWhile { it.isEmpty() }.map { line -> line.trim { it <= ' ' } }) {
if (line.startsWith("LINENUMBER")) {
if (byteCodeStartLine < 0 && ktLineNum == startLine) { val ktLineNum = Scanner(line.substring("LINENUMBER".length)).nextInt() - 1
byteCodeStartLine = byteCodeLine; lines.add(ktLineNum)
} }
}
Collections.sort(lines)
if (byteCodeStartLine > 0 && ktLineNum > endLine) { for (line in lines) {
byteCodeEndLine = byteCodeLine - 1; if (line >= startLine) {
break; startLine = line
break
} }
} }
if (byteCodeStartLine >= 0 && (line.startsWith("MAXSTACK") || line.startsWith("LOCALVARIABLE") || line.isEmpty())) { for (line in text.split("\n").dropLastWhile { it.isEmpty() }.map { line -> line.trim { it <= ' ' } }) {
byteCodeEndLine = byteCodeLine - 1; if (line.startsWith("LINENUMBER")) {
break; val ktLineNum = Scanner(line.substring("LINENUMBER".length)).nextInt() - 1
if (byteCodeStartLine < 0 && ktLineNum == startLine) {
byteCodeStartLine = byteCodeLine
}
if (byteCodeStartLine > 0 && ktLineNum > endLine) {
byteCodeEndLine = byteCodeLine - 1
break
}
}
if (byteCodeStartLine >= 0 && (line.startsWith("MAXSTACK") || line.startsWith("LOCALVARIABLE") || line.isEmpty())) {
byteCodeEndLine = byteCodeLine - 1
break
}
byteCodeLine++
} }
return if (byteCodeStartLine == -1 || byteCodeEndLine == -1) {
byteCodeLine++; Pair(0, 0)
} } else {
Pair(byteCodeStartLine, byteCodeEndLine)
if (byteCodeStartLine == -1 || byteCodeEndLine == -1) {
return new Pair<Integer, Integer>(0, 0);
}
else {
return new Pair<Integer, Integer>(byteCodeStartLine, byteCodeEndLine);
}
}
private static String printStackTraceToString(Throwable e) {
StringWriter out = new StringWriter(1024);
try (PrintWriter printWriter = new PrintWriter(out)) {
e.printStackTrace(printWriter);
return out.toString().replace("\r", "");
}
}
private void setText(@NotNull final String resultText) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
myEditor.getDocument().setText(StringUtil.convertLineSeparators(resultText));
} }
}); }
}
@Override private fun printStackTraceToString(e: Throwable): String {
public void dispose() { val out = StringWriter(1024)
EditorFactory.getInstance().releaseEditor(myEditor); PrintWriter(out).use { printWriter ->
e.printStackTrace(printWriter)
return out.toString().replace("\r", "")
}
}
} }
} }