diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt index 2b28584d04d..2c5183292e9 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -47,8 +47,7 @@ fun getFunctionForExtractedFragment( ): JetNamedFunction? { fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String { - return analysisResult.messages.map { - errorMessage -> + 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}" @@ -60,8 +59,8 @@ fun getFunctionForExtractedFragment( ErrorMessage.MULTIPLE_EXIT_POINTS, ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression" } - if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}" - }.makeString(", ") + errorMessage.additionalInfo?.let { "$message: ${it.joinToString(", ")}" } ?: message + }.joinToString(", ") } return ApplicationManager.getApplication()?.runReadAction(object: Computable { diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt index ee78829849a..b52cb631bd3 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt @@ -37,6 +37,7 @@ import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Error import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor import org.jetbrains.jet.lang.psi.JetProperty import org.jetbrains.jet.lang.psi.JetDeclaration +import com.intellij.openapi.util.text.StringUtil trait Parameter { val argumentText: String @@ -193,21 +194,21 @@ class AnalysisResult ( } fun renderMessage(): String { - val message = JetRefactoringBundle.message(when(this) { - NO_EXPRESSION -> "cannot.refactor.no.expression" - NO_CONTAINER -> "cannot.refactor.no.container" - SUPER_CALL -> "cannot.extract.super.call" - DENOTABLE_TYPES -> "parameter.types.are.not.denotable" - MULTIPLE_OUTPUT -> "selected.code.fragment.has.multiple.output.values" - OUTPUT_AND_EXIT_POINT -> "selected.code.fragment.has.output.values.and.exit.points" - MULTIPLE_EXIT_POINTS -> "selected.code.fragment.has.multiple.exit.points" - DECLARATIONS_ARE_USED_OUTSIDE -> "declarations.are.used.outside.of.selected.code.fragment" - DECLARATIONS_OUT_OF_SCOPE -> "declarations.will.move.out.of.scope" - })!! - if (additionalInfo != null) { - return "$message\n${additionalInfo?.makeString("\n")}" - } - return message + val message = JetRefactoringBundle.message( + when (this) { + NO_EXPRESSION -> "cannot.refactor.no.expression" + NO_CONTAINER -> "cannot.refactor.no.container" + SUPER_CALL -> "cannot.extract.super.call" + DENOTABLE_TYPES -> "parameter.types.are.not.denotable" + MULTIPLE_OUTPUT -> "selected.code.fragment.has.multiple.output.values" + OUTPUT_AND_EXIT_POINT -> "selected.code.fragment.has.output.values.and.exit.points" + MULTIPLE_EXIT_POINTS -> "selected.code.fragment.has.multiple.exit.points" + DECLARATIONS_ARE_USED_OUTSIDE -> "declarations.are.used.outside.of.selected.code.fragment" + DECLARATIONS_OUT_OF_SCOPE -> "declarations.will.move.out.of.scope" + } + ) + + return additionalInfo?.let { "$message\n\n${it.map { StringUtil.htmlEmphasize(it) }.joinToString("\n")}" } ?: message } } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 246edb6a38c..ec3e4b2fbb1 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -68,11 +68,21 @@ import org.jetbrains.jet.lang.resolve.OverridingUtil import org.jetbrains.jet.lang.psi.psiUtil.isAncestor import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils +import com.intellij.openapi.util.text.StringUtil private val DEFAULT_FUNCTION_NAME = "myFun" private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType() +private fun DeclarationDescriptor.renderForMessage(): String = + DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(this) + +private fun JetType.renderForMessage(): String = + DescriptorRenderer.SOURCE_CODE.renderType(this) + +private fun JetDeclaration.renderForMessage(bindingContext: BindingContext): String? = + bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this]?.renderForMessage() + private fun JetType.isDefault(): Boolean = KotlinBuiltIns.getInstance().isUnit(this) private fun List.getModifiedVarDescriptors(bindingContext: BindingContext): Set { @@ -203,7 +213,7 @@ private fun ExtractionData.analyzeControlFlow( val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow, declarationsToCopy) if (declarationsToReport.isNotEmpty()) { - val localVarStr = declarationsToReport.map { it.getName()!! }.sort() + val localVarStr = declarationsToReport.map { it.renderForMessage(bindingContext)!! }.distinct().sort() return Pair(defaultControlFlow, ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE.addAdditionalInfo(localVarStr)) } @@ -214,7 +224,9 @@ private fun ExtractionData.analyzeControlFlow( val outValuesCount = outDeclarations.size + outParameters.size when { outValuesCount > 1 -> { - val outValuesStr = (outParameters.map { it.argumentText } + outDeclarations.map { it.getName()!! }).sort() + val outValuesStr = + (outParameters.map { it.originalDescriptor.renderForMessage() } + + outDeclarations.map { it.renderForMessage(bindingContext)!! }).sort() return Pair(defaultControlFlow, ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr)) } @@ -532,7 +544,8 @@ private fun ExtractionData.inferParametersInfo( private fun ExtractionData.checkDeclarationsMovingOutOfScope( enclosingDeclaration: JetDeclaration, - controlFlow: ControlFlow + controlFlow: ControlFlow, + bindingContext: BindingContext ): ErrorMessage? { val declarationsOutOfScope = HashSet() if (controlFlow is JumpBasedControlFlow) { @@ -551,7 +564,7 @@ private fun ExtractionData.checkDeclarationsMovingOutOfScope( } if (declarationsOutOfScope.isNotEmpty()) { - val declStr = declarationsOutOfScope.map { it.getName()!! }.sort() + val declStr = declarationsOutOfScope.map { it.renderForMessage(bindingContext)!! }.sort() return ErrorMessage.DECLARATIONS_OUT_OF_SCOPE.addAdditionalInfo(declStr) } @@ -614,7 +627,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult { controlFlow.returnType.processTypeIfExtractable(paramsInfo.typeParameters, paramsInfo.nonDenotableTypes) if (paramsInfo.nonDenotableTypes.isNotEmpty()) { - val typeStr = paramsInfo.nonDenotableTypes.map {DescriptorRenderer.HTML.renderType(it)}.sort() + val typeStr = paramsInfo.nonDenotableTypes.map {it.renderForMessage()}.sort() return AnalysisResult( null, Status.CRITICAL_ERROR, @@ -622,7 +635,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult { ) } - checkDeclarationsMovingOutOfScope(enclosingDeclaration!!, controlFlow)?.let { messages.add(it) } + checkDeclarationsMovingOutOfScope(enclosingDeclaration!!, controlFlow, bindingContext)?.let { messages.add(it) } val functionNameValidator = JetNameValidatorImpl( @@ -689,9 +702,9 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts { && parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue if (diagnostics.any { it.getFactory() == Errors.UNRESOLVED_REFERENCE } - || (currentDescriptor != null - && !ErrorUtils.isError(currentDescriptor) - && !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) { + || (currentDescriptor != null + && !ErrorUtils.isError(currentDescriptor) + && !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) { conflicts.putValue( resolveResult.originalRefExpr, JetRefactoringBundle.message( diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment index a578944eca6..1f25bd696e0 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment @@ -2,4 +2,4 @@ prop += 1 prop2 +=2 prop + prop2 -// RESULT: Cannot perform an action because this code fragment changes more than one variable: prop, prop2 \ No newline at end of file +// RESULT: Cannot perform an action because this code fragment changes more than one variable: var prop2: Int, var prop: Int \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 index b2bb2bedf84..5c0118fd9f6 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 @@ -1,3 +1,3 @@ object {} -// RESULT: Cannot perform an action because following types are unavailable from debugger scope: errors.MyClass.baseFun.<no name provided> \ No newline at end of file +// RESULT: Cannot perform an action because following types are unavailable from debugger scope: errors.MyClass.baseFun. \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt.conflicts b/idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt.conflicts index 626e9188d07..8502fb23530 100644 --- a/idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/basic/localClassPropertyRef.kt.conflicts b/idea/testData/refactoring/extractFunction/basic/localClassPropertyRef.kt.conflicts index 626e9188d07..8502fb23530 100644 --- a/idea/testData/refactoring/extractFunction/basic/localClassPropertyRef.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/basic/localClassPropertyRef.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/basic/localObjectRef.kt.conflicts b/idea/testData/refactoring/extractFunction/basic/localObjectRef.kt.conflicts index 626e9188d07..8502fb23530 100644 --- a/idea/testData/refactoring/extractFunction/basic/localObjectRef.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/basic/localObjectRef.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.A \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValues.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValues.kt.conflicts index a0bfaa64039..c53e0fcc3ef 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValues.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValues.kt.conflicts @@ -1 +1 @@ -Selected code fragment has multiple output values: b c \ No newline at end of file +Selected code fragment has multiple output values: var b: Int var c: Int \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithIf.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithIf.kt.conflicts index a0bfaa64039..c53e0fcc3ef 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithIf.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithIf.kt.conflicts @@ -1 +1 @@ -Selected code fragment has multiple output values: b c \ No newline at end of file +Selected code fragment has multiple output values: var b: Int var c: Int \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithWhen.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithWhen.kt.conflicts index a0bfaa64039..c53e0fcc3ef 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithWhen.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithWhen.kt.conflicts @@ -1 +1 @@ -Selected code fragment has multiple output values: b c \ No newline at end of file +Selected code fragment has multiple output values: var b: Int var c: Int \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/anonymousObject.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/anonymousObject.kt.conflicts index 0ef37503755..4c1b8de6ccc 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/anonymousObject.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/anonymousObject.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.<no name provided> +Cannot extract method since following types are not denotable in the target scope: foo.<no name provided> \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt.conflicts index a4c58b33e7a..140c9346d58 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt.conflicts @@ -1 +1 @@ -Selected code fragment has multiple output values: a b \ No newline at end of file +Selected code fragment has multiple output values: val a: Int val b: Int \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt.conflicts index 8ef3b3ff76a..8678f835d6c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt.conflicts @@ -1 +1 @@ -Following declarations won't be available outside of extracted function body: x +Following declarations won't be available outside of extracted function body: val x: Int \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParameters.kt.conflicts b/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParameters.kt.conflicts index d6e7ed6edfd..6ed3da8069a 100644 --- a/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParameters.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParameters.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: [ERROR : ] \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: [ERROR : <ERROR FUNCTION RETURN TYPE>] \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParametersWithLambda.kt.conflicts b/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParametersWithLambda.kt.conflicts index d6e7ed6edfd..6ed3da8069a 100644 --- a/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParametersWithLambda.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/initializers/functions/localFunctionParametersWithLambda.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: [ERROR : ] \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: [ERROR : <ERROR FUNCTION RETURN TYPE>] \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/anonymousObject.kt.conflicts b/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/anonymousObject.kt.conflicts index f121223719e..4c1b8de6ccc 100644 --- a/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/anonymousObject.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/anonymousObject.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.<no name provided> \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.<no name provided> \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/localClass.kt.conflicts b/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/localClass.kt.conflicts index 7caf9b8e1f9..48996644624 100644 --- a/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/localClass.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes/localClass.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.T \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.T \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/typeParameters/localClassInBound.kt.conflicts b/idea/testData/refactoring/extractFunction/typeParameters/localClassInBound.kt.conflicts index eb6536d308e..ea41294ec2a 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/localClassInBound.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/typeParameters/localClassInBound.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.X \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.X \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/typeParameters/localClassInTypeConstraint.kt.conflicts b/idea/testData/refactoring/extractFunction/typeParameters/localClassInTypeConstraint.kt.conflicts index eb6536d308e..ea41294ec2a 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/localClassInTypeConstraint.kt.conflicts +++ b/idea/testData/refactoring/extractFunction/typeParameters/localClassInTypeConstraint.kt.conflicts @@ -1 +1 @@ -Cannot extract method since following types are not denotable in the target scope: foo.X \ No newline at end of file +Cannot extract method since following types are not denotable in the target scope: foo.X \ No newline at end of file