Evaluate expression: move helper methods for extract function to separate file
This commit is contained in:
@@ -43,17 +43,9 @@ import org.jetbrains.eval4j.jdi.asJdiValue
|
|||||||
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
|
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
|
||||||
import org.jetbrains.eval4j.jdi.asValue
|
import org.jetbrains.eval4j.jdi.asValue
|
||||||
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction
|
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import org.jetbrains.jet.codegen.ClassFileFactory
|
import org.jetbrains.jet.codegen.ClassFileFactory
|
||||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
|
||||||
import org.jetbrains.jet.OutputFileCollection
|
import org.jetbrains.jet.OutputFileCollection
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults
|
import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults
|
||||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||||
@@ -63,15 +55,11 @@ import org.jetbrains.jet.lang.psi.JetExpression
|
|||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import org.jetbrains.jet.codegen.CompilationErrorHandler
|
import org.jetbrains.jet.codegen.CompilationErrorHandler
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
|
||||||
import org.jetbrains.jet.lang.diagnostics.Severity
|
import org.jetbrains.jet.lang.diagnostics.Severity
|
||||||
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages
|
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages
|
||||||
import com.sun.jdi.request.EventRequest
|
import com.sun.jdi.request.EventRequest
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.ObjectReference
|
||||||
import com.intellij.debugger.engine.SuspendContext
|
import com.intellij.debugger.engine.SuspendContext
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
|
||||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder
|
|
||||||
|
|
||||||
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
||||||
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
||||||
@@ -271,38 +259,6 @@ private fun createFileForDebugger(codeFragment: JetCodeFragment,
|
|||||||
return jetFile
|
return jetFile
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) {
|
|
||||||
if (newImportList != null) {
|
|
||||||
val tmpFileImportList = tmpFile.getImportList()
|
|
||||||
val packageDirective = tmpFile.getPackageDirective()
|
|
||||||
if (tmpFileImportList == null) {
|
|
||||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
|
||||||
tmpFile.addAfter(newImportList, tmpFile.getPackageDirective())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tmpFileImportList.replace(newImportList)
|
|
||||||
}
|
|
||||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? {
|
|
||||||
val parent = contextElement.getParent()
|
|
||||||
if (parent == null) return null
|
|
||||||
|
|
||||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
|
||||||
|
|
||||||
val debugExpression = codeFragment.getContentElement()
|
|
||||||
if (debugExpression == null) return null
|
|
||||||
|
|
||||||
val newDebugExpression = parent.addBefore(debugExpression, contextElement)
|
|
||||||
if (newDebugExpression == null) return null
|
|
||||||
|
|
||||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
|
||||||
|
|
||||||
return newDebugExpression as JetExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
fun checkForSyntacticErrors(file: JetFile) {
|
fun checkForSyntacticErrors(file: JetFile) {
|
||||||
try {
|
try {
|
||||||
AnalyzingUtils.checkForSyntacticErrors(file)
|
AnalyzingUtils.checkForSyntacticErrors(file)
|
||||||
@@ -312,69 +268,3 @@ fun checkForSyntacticErrors(file: JetFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFunctionForExtractedFragment(
|
|
||||||
codeFragment: JetCodeFragment,
|
|
||||||
breakpointFile: PsiFile,
|
|
||||||
breakpointLine: Int
|
|
||||||
): JetNamedFunction? {
|
|
||||||
|
|
||||||
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String {
|
|
||||||
return analysisResult.messages.map {
|
|
||||||
errorMessage ->
|
|
||||||
val message = when(errorMessage) {
|
|
||||||
ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression"
|
|
||||||
ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}"
|
|
||||||
ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call"
|
|
||||||
ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope"
|
|
||||||
ErrorMessage.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable"
|
|
||||||
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
|
||||||
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
|
||||||
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
|
||||||
ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
|
||||||
}
|
|
||||||
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
|
||||||
}.makeString(", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApplicationManager.getApplication()?.runReadAction(object: Computable<JetNamedFunction> {
|
|
||||||
override fun compute(): JetNamedFunction? {
|
|
||||||
checkForSyntacticErrors(codeFragment)
|
|
||||||
|
|
||||||
val originalFile = breakpointFile as JetFile
|
|
||||||
|
|
||||||
val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine)
|
|
||||||
if (lineStart == null) return null
|
|
||||||
|
|
||||||
val tmpFile = originalFile.createTempCopy { it }
|
|
||||||
tmpFile.skipVisibilityCheck = true
|
|
||||||
|
|
||||||
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
|
||||||
if (elementAtOffset == null) return null
|
|
||||||
|
|
||||||
val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
|
||||||
|
|
||||||
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
|
||||||
|
|
||||||
val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
|
||||||
if (newDebugExpression == null) return null
|
|
||||||
|
|
||||||
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
|
||||||
if (targetSibling == null) return null
|
|
||||||
|
|
||||||
val analysisResult = ExtractionData(
|
|
||||||
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false)
|
|
||||||
).performAnalysis()
|
|
||||||
if (analysisResult.status != Status.SUCCESS) {
|
|
||||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
|
||||||
}
|
|
||||||
|
|
||||||
val validationResult = analysisResult.descriptor!!.validate()
|
|
||||||
if (!validationResult.conflicts.isEmpty()) {
|
|
||||||
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return validationResult.descriptor.generateFunction(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.jet.plugin.debugger.evaluate
|
||||||
|
|
||||||
|
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.util.Computable
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFile
|
||||||
|
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
||||||
|
import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData
|
||||||
|
import java.util.Collections
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||||
|
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction
|
||||||
|
import org.jetbrains.jet.lang.psi.JetImportList
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||||
|
|
||||||
|
fun getFunctionForExtractedFragment(
|
||||||
|
codeFragment: JetCodeFragment,
|
||||||
|
breakpointFile: PsiFile,
|
||||||
|
breakpointLine: Int
|
||||||
|
): JetNamedFunction? {
|
||||||
|
|
||||||
|
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String {
|
||||||
|
return analysisResult.messages.map {
|
||||||
|
errorMessage ->
|
||||||
|
val message = when(errorMessage) {
|
||||||
|
ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression"
|
||||||
|
ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}"
|
||||||
|
ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call"
|
||||||
|
ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope"
|
||||||
|
ErrorMessage.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable"
|
||||||
|
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
||||||
|
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
||||||
|
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
||||||
|
ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
||||||
|
}
|
||||||
|
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
||||||
|
}.makeString(", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApplicationManager.getApplication()?.runReadAction(object: Computable<JetNamedFunction> {
|
||||||
|
override fun compute(): JetNamedFunction? {
|
||||||
|
checkForSyntacticErrors(codeFragment)
|
||||||
|
|
||||||
|
val originalFile = breakpointFile as JetFile
|
||||||
|
|
||||||
|
val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine)
|
||||||
|
if (lineStart == null) return null
|
||||||
|
|
||||||
|
val tmpFile = originalFile.createTempCopy { it }
|
||||||
|
tmpFile.skipVisibilityCheck = true
|
||||||
|
|
||||||
|
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
||||||
|
if (elementAtOffset == null) return null
|
||||||
|
|
||||||
|
val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||||
|
|
||||||
|
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
||||||
|
|
||||||
|
val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
||||||
|
if (newDebugExpression == null) return null
|
||||||
|
|
||||||
|
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
||||||
|
if (targetSibling == null) return null
|
||||||
|
|
||||||
|
val analysisResult = ExtractionData(
|
||||||
|
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false)
|
||||||
|
).performAnalysis()
|
||||||
|
if (analysisResult.status != Status.SUCCESS) {
|
||||||
|
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
val validationResult = analysisResult.descriptor!!.validate()
|
||||||
|
if (!validationResult.conflicts.isEmpty()) {
|
||||||
|
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return validationResult.descriptor.generateFunction(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) {
|
||||||
|
if (newImportList != null) {
|
||||||
|
val tmpFileImportList = tmpFile.getImportList()
|
||||||
|
val packageDirective = tmpFile.getPackageDirective()
|
||||||
|
if (tmpFileImportList == null) {
|
||||||
|
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||||
|
tmpFile.addAfter(newImportList, tmpFile.getPackageDirective())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tmpFileImportList.replace(newImportList)
|
||||||
|
}
|
||||||
|
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? {
|
||||||
|
val parent = contextElement.getParent()
|
||||||
|
if (parent == null) return null
|
||||||
|
|
||||||
|
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||||
|
|
||||||
|
val debugExpression = codeFragment.getContentElement()
|
||||||
|
if (debugExpression == null) return null
|
||||||
|
|
||||||
|
val newDebugExpression = parent.addBefore(debugExpression, contextElement)
|
||||||
|
if (newDebugExpression == null) return null
|
||||||
|
|
||||||
|
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||||
|
|
||||||
|
return newDebugExpression as JetExpression
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user