KotlinBytecodeToolWindow: convert to .kt
This commit is contained in:
+275
-327
@@ -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", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user