Correct handling of erroneous code during code extraction

This commit is contained in:
Mikhail Glukhikh
2016-02-12 11:17:22 +03:00
parent eed4aa71db
commit 5def6eae5b
8 changed files with 31 additions and 10 deletions
@@ -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<PseudoValue
return results
}
fun KtElement.getContainingPseudocode(context: BindingContext): Pseudocode? {
val pseudocodeDeclaration =
PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
?: getNonStrictParentOfType<KtProperty>()
?: return null
val KtElement.containingDeclarationForPseudocode: KtDeclaration?
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
?: getNonStrictParentOfType<KtProperty>()
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
@@ -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"
@@ -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
@@ -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"
@@ -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)
@@ -0,0 +1,8 @@
// EXTRACTION_TARGET: property with getter
fun doSomethingStrangeWithCollection(collection: Collection<String>): Collection<String>? {
val groupsByLength = collection.groupBy { s -> { s.length } }
val maximumSizeOfGroup = groupsByLength.values.maxBy { it.size }.
return groupsByLength.values.firstOrNull { group -> {<selection>group.size == maximumSizeOfGroup</selection>} }
}
@@ -0,0 +1 @@
Cannot refactor due to erroneous code
@@ -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");