From 7671962284ac47c2dc7b4a23e104f0ae85ecace0 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 28 May 2014 15:09:55 +0400 Subject: [PATCH] Evaluate expression: move helper methods for extract function to separate file --- .../evaluate/KotlinEvaluationBuilder.kt | 110 -------------- .../extractFunctionForDebuggerUtil.kt | 139 ++++++++++++++++++ 2 files changed, 139 insertions(+), 110 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index b039b139d48..189f27bd444 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -43,17 +43,9 @@ import org.jetbrains.eval4j.jdi.asJdiValue import org.jetbrains.eval4j.jdi.makeInitialFrame import org.jetbrains.jet.lang.resolve.java.PackageClassUtils import org.jetbrains.jet.lang.resolve.name.FqName -import org.jetbrains.jet.lang.psi.JetPsiFactory 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 com.intellij.psi.PsiFile import org.jetbrains.jet.codegen.ClassFileFactory -import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils import org.jetbrains.jet.OutputFileCollection import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults 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 com.intellij.openapi.diagnostic.Logger 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.rendering.DefaultErrorMessages import com.sun.jdi.request.EventRequest import com.sun.jdi.ObjectReference import com.intellij.debugger.engine.SuspendContext -import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions -import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder object KotlinEvaluationBuilder: EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { @@ -271,38 +259,6 @@ private fun createFileForDebugger(codeFragment: JetCodeFragment, 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) { try { 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 { - 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) - } - }) -} - diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt new file mode 100644 index 00000000000..a932c5024db --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -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 { + 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 +}