Refactoring: extract method

This commit is contained in:
Natalia Ukhorskaya
2014-06-02 19:08:57 +04:00
parent 7671962284
commit a593738ca6
@@ -87,28 +87,55 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
) : Evaluator { ) : Evaluator {
override fun evaluate(context: EvaluationContextImpl): Any? { override fun evaluate(context: EvaluationContextImpl): Any? {
try { try {
val compiledData = extractAndCompile(codeFragment, sourcePosition)
return runEval4j(context, compiledData)
}
catch(e: EvaluateException) {
throw e
}
catch (e: Exception) {
logger.error("Couldn't evaluate expression:\nfileText = ${sourcePosition.getFile().getText()}\nline = ${sourcePosition.getLine()}\ncodeFragment = ${codeFragment.getText()}", e)
val cause = if (e.getMessage() != null) ": ${e.getMessage()}" else ""
exception("An exception occurs during Evaluate Expression Action $cause")
}
}
override fun getModifier(): Modifier? {
return null
}
class object {
private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition): CompiledDataDescriptor {
val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine()) val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine())
if (extractedFunction == null) { if (extractedFunction == null) {
throw IllegalStateException("Code fragment cannot be extracted to function: ${sourcePosition.getFile().getText()}:${sourcePosition.getLine()},\ncodeFragment = ${codeFragment.getText()}") throw IllegalStateException("Code fragment cannot be extracted to function: ${sourcePosition.getFile().getText()}:${sourcePosition.getLine()},\ncodeFragment = ${codeFragment.getText()}")
} }
val classFileFactory = createClassFileFactory(extractedFunction) val classFileFactory = createClassFileFactory(codeFragment, extractedFunction)
// KT-4509 // KT-4509
val outputFiles = (classFileFactory : OutputFileCollection).asList().filter { it.relativePath != "$packageInternalName.class" } val outputFiles = (classFileFactory : OutputFileCollection).asList().filter { it.relativePath != "$packageInternalName.class" }
if (outputFiles.size() != 1) exception("Expression compiles to more than one class file. Note that lambdas, classes and objects are unsupported yet. List of files: ${outputFiles.makeString(",")}") if (outputFiles.size() != 1) exception("Expression compiles to more than one class file. Note that lambdas, classes and objects are unsupported yet. List of files: ${outputFiles.makeString(",")}")
val funName = extractedFunction.getName()
if (funName == null) {
throw IllegalStateException("Extracted function should have a name: ${extractedFunction.getText()}")
}
return CompiledDataDescriptor(outputFiles.first().asByteArray(), funName, extractedFunction.getParameterNamesForDebugger())
}
private fun runEval4j(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? {
val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine() val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine()
var resultValue: Value? = null var resultValue: Value? = null
ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) { ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
if (name == extractedFunction.getName()) { if (name == compiledData.funName) {
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
override fun visitEnd() { override fun visitEnd() {
val value = interpreterLoop( val value = interpreterLoop(
this, this,
makeInitialFrame(this, context.getArgumentsByNames(extractedFunction.getParameterNamesForDebugger())), makeInitialFrame(this, context.getArgumentsByNames(compiledData.parameterNames)),
JDIEval(virtualMachine, JDIEval(virtualMachine,
context.getClassLoader()!!, context.getClassLoader()!!,
context.getSuspendContext().getThread()?.getThreadReference()!!, context.getSuspendContext().getInvokePolicy()) context.getSuspendContext().getThread()?.getThreadReference()!!, context.getSuspendContext().getInvokePolicy())
@@ -128,24 +155,11 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
}, 0) }, 0)
if (resultValue == null) { if (resultValue == null) {
throw IllegalStateException("resultValue is null: cannot find method ${extractedFunction.getName()} in ${outputFiles.first().relativePath}") throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}")
} }
return resultValue!!.asJdiValue(virtualMachine, resultValue!!.asmType) return resultValue!!.asJdiValue(virtualMachine, resultValue!!.asmType)
} }
catch(e: EvaluateException) {
throw e
}
catch (e: Exception) {
logger.error("Couldn't evaluate expression:\nfileText = ${sourcePosition.getFile().getText()}\nline = ${sourcePosition.getLine()}\ncodeFragment = ${codeFragment.getText()}", e)
val cause = if (e.getMessage() != null) ": ${e.getMessage()}" else ""
exception("An exception occurs during Evaluate Expression Action $cause")
}
}
override fun getModifier(): Modifier? {
return null
}
private fun SuspendContext.getInvokePolicy(): Int { private fun SuspendContext.getInvokePolicy(): Int {
return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0 return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0
@@ -182,8 +196,8 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
return Collections.emptyList() return Collections.emptyList()
} }
private fun createClassFileFactory(extractedFunction: JetNamedFunction): ClassFileFactory { private fun createClassFileFactory(codeFragment: JetCodeFragment, extractedFunction: JetNamedFunction): ClassFileFactory {
return ApplicationManager.getApplication()?.runReadAction(object: Computable<ClassFileFactory> { return ApplicationManager.getApplication()?.runReadAction(object : Computable<ClassFileFactory> {
override fun compute(): ClassFileFactory? { override fun compute(): ClassFileFactory? {
val file = createFileForDebugger(codeFragment, extractedFunction) val file = createFileForDebugger(codeFragment, extractedFunction)
@@ -227,6 +241,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
} }
throw EvaluateExceptionUtil.createEvaluateException(e) throw EvaluateExceptionUtil.createEvaluateException(e)
} }
}
} }
private val template = """ private val template = """
@@ -268,3 +283,6 @@ fun checkForSyntacticErrors(file: JetFile) {
} }
} }
data class CompiledDataDescriptor(val bytecodes: ByteArray, val funName: String, val parameterNames: List<String>)