From 5def6eae5b9ca27a99f5458cbb764d4bdfe58db2 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 12 Feb 2016 11:17:22 +0300 Subject: [PATCH] Correct handling of erroneous code during code extraction --- .../kotlin/cfg/pseudocode/pseudocodeUtils.kt | 18 +++++++++--------- .../evaluate/extractFunctionForDebuggerUtil.kt | 1 + .../KotlinRefactoringBundle.properties | 1 + .../ExtractableCodeDescriptor.kt | 2 ++ .../extractableAnalysisUtil.kt | 4 +++- .../introduceProperty/syntaxErrors.kt | 8 ++++++++ .../syntaxErrors.kt.conflicts | 1 + .../introduce/ExtractionTestGenerated.java | 6 ++++++ 8 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 idea/testData/refactoring/introduceProperty/syntaxErrors.kt create mode 100644 idea/testData/refactoring/introduceProperty/syntaxErrors.kt.conflicts diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtils.kt index 2845f5dcc0e..43de2fa24d5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtils.kt @@ -27,7 +27,6 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInst import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.parents @@ -287,20 +286,21 @@ fun Pseudocode.getElementValuesRecursively(element: KtElement): List() - ?: return null +val KtElement.containingDeclarationForPseudocode: KtDeclaration? + get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java) + ?: getNonStrictParentOfType() - val enclosingPseudocodeDeclaration = (pseudocodeDeclaration as? KtFunctionLiteral)?.let { +fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode? { + val enclosingPseudocodeDeclaration = (this as? KtFunctionLiteral)?.let { it.parents.firstOrNull { it is KtDeclaration && it !is KtFunctionLiteral } as? KtDeclaration - } ?: pseudocodeDeclaration + } ?: this val enclosingPseudocode = PseudocodeUtil.generatePseudocode(enclosingPseudocodeDeclaration, context) - return enclosingPseudocode.getPseudocodeByElement(pseudocodeDeclaration) + return enclosingPseudocode.getPseudocodeByElement(this) } +fun KtElement.getContainingPseudocode(context: BindingContext) = containingDeclarationForPseudocode?.getContainingPseudocode(context) + fun Pseudocode.getPseudocodeByElement(element: KtElement): Pseudocode? { if (correspondingElement == element) return this diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt index 741f5f16080..2908de50b6f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -56,6 +56,7 @@ fun getFunctionForExtractedFragment( 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.name}:$breakpointLine" + ErrorMessage.SYNTAX_ERRORS -> "Cannot perform an action due to erroneous code" 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.ERROR_TYPES -> "Cannot perform an action because this code fragment contains erroneous types" diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties b/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties index 4a5f90f2f6f..1ad971e3b11 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties @@ -6,6 +6,7 @@ introduce.property=Introduce Property introduce.parameter=Introduce Parameter cannot.refactor.no.container=Cannot refactor in this place cannot.refactor.no.expression=Cannot perform refactoring without an expression +cannot.refactor.syntax.errors=Cannot refactor due to erroneous code cannot.refactor.expression.has.unit.type=Cannot introduce expression of unit type cannot.refactor.package.expression=Cannot introduce package reference extract.function=Extract Function diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt index 24f3a3bcce7..8823abc3157 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt @@ -505,6 +505,7 @@ class AnalysisResult ( enum class ErrorMessage { NO_EXPRESSION, NO_CONTAINER, + SYNTAX_ERRORS, SUPER_CALL, DENOTABLE_TYPES, ERROR_TYPES, @@ -526,6 +527,7 @@ class AnalysisResult ( when (this) { NO_EXPRESSION -> "cannot.refactor.no.expression" NO_CONTAINER -> "cannot.refactor.no.container" + SYNTAX_ERRORS -> "cannot.refactor.syntax.errors" SUPER_CALL -> "cannot.extract.super.call" DENOTABLE_TYPES -> "parameter.types.are.not.denotable" ERROR_TYPES -> "error.types.in.generated.function" diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index 7bfa2b20d47..74a79c50612 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -624,7 +624,9 @@ fun ExtractionData.performAnalysis(): AnalysisResult { val bindingContext = bindingContext ?: return noContainerError - val pseudocode = commonParent.getContainingPseudocode(bindingContext) ?: return noContainerError + val declaration = commonParent.containingDeclarationForPseudocode ?: return noContainerError + val pseudocode = declaration.getContainingPseudocode(bindingContext) + ?: return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(ErrorMessage.SYNTAX_ERRORS)) val localInstructions = getLocalInstructions(pseudocode) val modifiedVarDescriptorsWithExpressions = localInstructions.getModifiedVarDescriptors(bindingContext) diff --git a/idea/testData/refactoring/introduceProperty/syntaxErrors.kt b/idea/testData/refactoring/introduceProperty/syntaxErrors.kt new file mode 100644 index 00000000000..4b25ff08905 --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/syntaxErrors.kt @@ -0,0 +1,8 @@ +// EXTRACTION_TARGET: property with getter + +fun doSomethingStrangeWithCollection(collection: Collection): Collection? { + val groupsByLength = collection.groupBy { s -> { s.length } } + + val maximumSizeOfGroup = groupsByLength.values.maxBy { it.size }. + return groupsByLength.values.firstOrNull { group -> {group.size == maximumSizeOfGroup} } +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceProperty/syntaxErrors.kt.conflicts b/idea/testData/refactoring/introduceProperty/syntaxErrors.kt.conflicts new file mode 100644 index 00000000000..3c4fc82db4c --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/syntaxErrors.kt.conflicts @@ -0,0 +1 @@ +Cannot refactor due to erroneous code \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index e39a15a0b7f..b022139b2e6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -3124,6 +3124,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doIntroducePropertyTest(fileName); } + @TestMetadata("syntaxErrors.kt") + public void testSyntaxErrors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/syntaxErrors.kt"); + doIntroducePropertyTest(fileName); + } + @TestMetadata("typeParameterNotResolvableInTargetScope.kt") public void testTypeParameterNotResolvableInTargetScope() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/typeParameterNotResolvableInTargetScope.kt");