Minor: Reformat extraction engine files

This commit is contained in:
Yan Zhulanow
2019-01-14 20:06:45 +03:00
parent 488418d960
commit ed88020a84
7 changed files with 698 additions and 593 deletions
@@ -81,7 +81,7 @@ class RenameReplacement(override val parameter: Parameter): ParameterReplacement
override fun copy(parameter: Parameter) = RenameReplacement(parameter) override fun copy(parameter: Parameter) = RenameReplacement(parameter)
override fun invoke(descriptor: ExtractableCodeDescriptor, e: KtElement): KtElement { override fun invoke(descriptor: ExtractableCodeDescriptor, e: KtElement): KtElement {
var expressionToReplace = (e.parent as? KtThisExpression ?: e).let { it.getQualifiedExpressionForSelector() ?: it } val expressionToReplace = (e.parent as? KtThisExpression ?: e).let { it.getQualifiedExpressionForSelector() ?: it }
val parameterName = KtPsiUtil.unquoteIdentifier(parameter.nameForRef) val parameterName = KtPsiUtil.unquoteIdentifier(parameter.nameForRef)
val replacingName = val replacingName =
if (e.text.startsWith('`') || !parameterName.isIdentifier()) "`$parameterName`" else parameterName if (e.text.startsWith('`') || !parameterName.isIdentifier()) "`$parameterName`" else parameterName
@@ -281,7 +281,7 @@ abstract class OutputValueBoxer(val outputValues: List<OutputValue>) {
) )
} }
override val boxingRequired: Boolean = outputValues.size > 0 override val boxingRequired: Boolean = outputValues.isNotEmpty()
override fun getBoxingExpressionPattern(arguments: List<KtExpression>): String? { override fun getBoxingExpressionPattern(arguments: List<KtExpression>): String? {
if (arguments.isEmpty()) return null if (arguments.isEmpty()) return null
@@ -377,8 +377,7 @@ fun ExtractableCodeDescriptor.copy(
val parameter = it.parameter val parameter = it.parameter
val newParameter = oldToNewParameters[parameter] ?: return@map it val newParameter = oldToNewParameters[parameter] ?: return@map it
it.copy(newParameter) it.copy(newParameter)
} } else it
else it
} }
newReplacementMap.putValues(ref, newReplacements) newReplacementMap.putValues(ref, newReplacements)
} }
@@ -394,7 +393,8 @@ fun ExtractableCodeDescriptor.copy(
newReplacementMap, newReplacementMap,
controlFlow.copy(oldToNewParameters), controlFlow.copy(oldToNewParameters),
returnType ?: this.returnType, returnType ?: this.returnType,
modifiers) modifiers
)
} }
enum class ExtractionTarget(val targetName: String) { enum class ExtractionTarget(val targetName: String) {
@@ -461,9 +461,11 @@ enum class ExtractionTarget(val targetName: String) {
} }
} }
val propertyTargets: List<ExtractionTarget> = listOf(ExtractionTarget.PROPERTY_WITH_INITIALIZER, val propertyTargets: List<ExtractionTarget> = listOf(
ExtractionTarget.PROPERTY_WITH_INITIALIZER,
ExtractionTarget.PROPERTY_WITH_GETTER, ExtractionTarget.PROPERTY_WITH_GETTER,
ExtractionTarget.LAZY_PROPERTY) ExtractionTarget.LAZY_PROPERTY
)
data class ExtractionGeneratorOptions( data class ExtractionGeneratorOptions(
val inTempFile: Boolean = false, val inTempFile: Boolean = false,
@@ -473,7 +475,8 @@ data class ExtractionGeneratorOptions(
val delayInitialOccurrenceReplacement: Boolean = false val delayInitialOccurrenceReplacement: Boolean = false
) { ) {
companion object { companion object {
@JvmField val DEFAULT = ExtractionGeneratorOptions() @JvmField
val DEFAULT = ExtractionGeneratorOptions()
} }
} }
@@ -538,7 +541,7 @@ class AnalysisResult (
} }
) )
return additionalInfo?.let { "$message\n\n${it.joinToString("\n") { StringUtil.htmlEmphasize(it) }}" } ?: message return additionalInfo?.let { "$message\n\n${it.joinToString("\n") { msg -> StringUtil.htmlEmphasize(msg) }}" } ?: message
} }
} }
} }
@@ -126,7 +126,7 @@ data class ExtractionData(
} }
private fun isExtractableIt(descriptor: DeclarationDescriptor, context: BindingContext): Boolean { private fun isExtractableIt(descriptor: DeclarationDescriptor, context: BindingContext): Boolean {
if (!(descriptor is ValueParameterDescriptor && (context[BindingContext.AUTO_CREATED_IT, descriptor] ?: false))) return false if (!(descriptor is ValueParameterDescriptor && (context[BindingContext.AUTO_CREATED_IT, descriptor] == true))) return false
val function = DescriptorToSourceUtils.descriptorToDeclaration(descriptor.containingDeclaration) as? KtFunctionLiteral val function = DescriptorToSourceUtils.descriptorToDeclaration(descriptor.containingDeclaration) as? KtFunctionLiteral
return function == null || !function.isInsideOf(physicalElements) return function == null || !function.isInsideOf(physicalElements)
} }
@@ -183,12 +183,15 @@ data class ExtractionData(
expressions.forEach { it.accept(visitor) } expressions.forEach { it.accept(visitor) }
} }
fun getPossibleTypes(expression: KtExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set<KotlinType> { private fun getPossibleTypes(expression: KtExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set<KotlinType> {
val dataFlowValueFactory = expression.getResolutionFacade().frontendService<DataFlowValueFactory>() val dataFlowValueFactory = expression.getResolutionFacade().frontendService<DataFlowValueFactory>()
val dataFlowInfo = context.getDataFlowInfoAfter(expression) val dataFlowInfo = context.getDataFlowInfoAfter(expression)
resolvedCall?.getImplicitReceiverValue()?.let { resolvedCall?.getImplicitReceiverValue()?.let {
return dataFlowInfo.getCollectedTypes(dataFlowValueFactory.createDataFlowValueForStableReceiver(it), expression.languageVersionSettings) return dataFlowInfo.getCollectedTypes(
dataFlowValueFactory.createDataFlowValueForStableReceiver(it),
expression.languageVersionSettings
)
} }
val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet() val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet()
@@ -223,9 +226,8 @@ data class ExtractionData(
shouldSkipPrimaryReceiver = smartCast == null shouldSkipPrimaryReceiver = smartCast == null
&& !DescriptorUtils.isCompanionObject(receiverDescriptor) && !DescriptorUtils.isCompanionObject(receiverDescriptor)
&& qualifiedExpression.receiverExpression !is KtSuperExpression && qualifiedExpression.receiverExpression !is KtSuperExpression
if (shouldSkipPrimaryReceiver && !(originalResolveResult.resolvedCall?.hasBothReceivers() ?: false)) continue if (shouldSkipPrimaryReceiver && originalResolveResult.resolvedCall?.hasBothReceivers() != true) continue
} } else {
else {
if (newRef.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null) continue if (newRef.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null) continue
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]?.defaultType smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]?.defaultType
possibleTypes = getPossibleTypes(originalResolveResult.originalRefExpr, originalResolveResult.resolvedCall, originalContext) possibleTypes = getPossibleTypes(originalResolveResult.originalRefExpr, originalResolveResult.resolvedCall, originalContext)
@@ -239,7 +241,9 @@ data class ExtractionData(
val descriptor = context[BindingContext.REFERENCE_TARGET, newRef] val descriptor = context[BindingContext.REFERENCE_TARGET, newRef]
val isBadRef = !(compareDescriptors(project, originalResolveResult.descriptor, descriptor) val isBadRef = !(compareDescriptors(project, originalResolveResult.descriptor, descriptor)
&& originalContext.diagnostics.forElement(originalResolveResult.originalRefExpr) == context.diagnostics.forElement(newRef)) && originalContext.diagnostics.forElement(originalResolveResult.originalRefExpr) == context.diagnostics.forElement(
newRef
))
|| smartCast != null || smartCast != null
if (isBadRef && !originalResolveResult.declaration.isInsideOf(physicalElements)) { if (isBadRef && !originalResolveResult.declaration.isInsideOf(physicalElements)) {
val originalResolvedCall = originalResolveResult.resolvedCall as? VariableAsFunctionResolvedCall val originalResolvedCall = originalResolveResult.resolvedCall as? VariableAsFunctionResolvedCall
@@ -248,16 +252,43 @@ data class ExtractionData(
val invokeDescriptor = originalFunctionCall?.resultingDescriptor val invokeDescriptor = originalFunctionCall?.resultingDescriptor
if (invokeDescriptor != null) { if (invokeDescriptor != null) {
val invokeDeclaration = getDeclaration(invokeDescriptor, context) ?: synthesizedInvokeDeclaration val invokeDeclaration = getDeclaration(invokeDescriptor, context) ?: synthesizedInvokeDeclaration
val variableResolveResult = originalResolveResult.copy(resolvedCall = originalVariableCall!!, val variableResolveResult = originalResolveResult.copy(
descriptor = originalVariableCall.resultingDescriptor) resolvedCall = originalVariableCall!!,
val functionResolveResult = originalResolveResult.copy(resolvedCall = originalFunctionCall, descriptor = originalVariableCall.resultingDescriptor
)
val functionResolveResult = originalResolveResult.copy(
resolvedCall = originalFunctionCall,
descriptor = originalFunctionCall.resultingDescriptor, descriptor = originalFunctionCall.resultingDescriptor,
declaration = invokeDeclaration) declaration = invokeDeclaration
referencesInfo.add(ResolvedReferenceInfo(newRef, variableResolveResult, smartCast, possibleTypes, shouldSkipPrimaryReceiver)) )
referencesInfo.add(ResolvedReferenceInfo(newRef, functionResolveResult, smartCast, possibleTypes, shouldSkipPrimaryReceiver)) referencesInfo.add(
} ResolvedReferenceInfo(
else { newRef,
referencesInfo.add(ResolvedReferenceInfo(newRef, originalResolveResult, smartCast, possibleTypes, shouldSkipPrimaryReceiver)) variableResolveResult,
smartCast,
possibleTypes,
shouldSkipPrimaryReceiver
)
)
referencesInfo.add(
ResolvedReferenceInfo(
newRef,
functionResolveResult,
smartCast,
possibleTypes,
shouldSkipPrimaryReceiver
)
)
} else {
referencesInfo.add(
ResolvedReferenceInfo(
newRef,
originalResolveResult,
smartCast,
possibleTypes,
shouldSkipPrimaryReceiver
)
)
} }
} }
} }
@@ -50,7 +50,8 @@ abstract class ExtractionEngineHelper(val operationName: String) {
class ExtractionEngine( class ExtractionEngine(
val helper: ExtractionEngineHelper val helper: ExtractionEngineHelper
) { ) {
fun run(editor: Editor, fun run(
editor: Editor,
extractionData: ExtractionData, extractionData: ExtractionData,
onFinish: (ExtractionResult) -> Unit = {} onFinish: (ExtractionResult) -> Unit = {}
) { ) {
@@ -68,8 +69,7 @@ class ExtractionEngine(
helper.configureAndRun(project, editor, validationResult) { helper.configureAndRun(project, editor, validationResult) {
try { try {
onFinish(it) onFinish(it)
} } finally {
finally {
it.dispose() it.dispose()
extractionData.dispose() extractionData.dispose()
} }
@@ -91,13 +91,12 @@ class ExtractionEngine(
JBPopupFactory.getInstance()!! JBPopupFactory.getInstance()!!
.createHtmlTextBalloonBuilder( .createHtmlTextBalloonBuilder(
"$message<br/><br/><a href=\"EXTRACT\">Proceed with extraction</a>", "$message<br/><br/><a href=\"EXTRACT\">Proceed with extraction</a>",
MessageType.WARNING, MessageType.WARNING
{ event -> ) { event ->
if (event?.eventType == HyperlinkEvent.EventType.ACTIVATED) { if (event?.eventType == HyperlinkEvent.EventType.ACTIVATED) {
validateAndRefactor() validateAndRefactor()
} }
} }
)
.setHideOnClickOutside(true) .setHideOnClickOutside(true)
.setHideOnFrameResize(false) .setHideOnFrameResize(false)
.setHideOnLinkClick(true) .setHideOnLinkClick(true)
@@ -48,21 +48,23 @@ fun KotlinPsiRange.highlight(project: Project, editor: Editor): RangeHighlighter
} }
fun KotlinPsiRange.preview(project: Project, editor: Editor): RangeHighlighter? { fun KotlinPsiRange.preview(project: Project, editor: Editor): RangeHighlighter? {
return highlight(project, editor)?.let { val highlight = highlight(project, editor) ?: return null
val startOffset = getPhysicalTextRange().startOffset val startOffset = getPhysicalTextRange().startOffset
val foldedRegions = val foldedRegions = CodeFoldingManager.getInstance(project)
CodeFoldingManager.getInstance(project)
.getFoldRegionsAtOffset(editor, startOffset) .getFoldRegionsAtOffset(editor, startOffset)
.filter { !it.isExpanded } .filter { !it.isExpanded }
if (!foldedRegions.isEmpty()) {
editor.foldingModel.runBatchFoldingOperation { foldedRegions.forEach { it.isExpanded = true } }
}
editor.scrollingModel.scrollTo(editor.offsetToLogicalPosition(startOffset), ScrollType.MAKE_VISIBLE)
it if (!foldedRegions.isEmpty()) {
editor.foldingModel.runBatchFoldingOperation {
foldedRegions.forEach { it.isExpanded = true }
} }
} }
editor.scrollingModel.scrollTo(editor.offsetToLogicalPosition(startOffset), ScrollType.MAKE_VISIBLE)
return highlight
}
fun processDuplicates( fun processDuplicates(
duplicateReplacers: Map<KotlinPsiRange, () -> Unit>, duplicateReplacers: Map<KotlinPsiRange, () -> Unit>,
project: Project, project: Project,
@@ -77,9 +79,9 @@ fun processDuplicates(
duplicateReplacers.keys.first().preview(project, editor) duplicateReplacers.keys.first().preview(project, editor)
} }
val answer = if (ApplicationManager.getApplication()!!.isUnitTestMode) val answer = if (ApplicationManager.getApplication()!!.isUnitTestMode) {
Messages.YES Messages.YES
else } else {
Messages.showYesNoDialog( Messages.showYesNoDialog(
project, project,
KotlinRefactoringBundle.message( KotlinRefactoringBundle.message(
@@ -92,7 +94,11 @@ fun processDuplicates(
"Process Duplicates", "Process Duplicates",
Messages.getQuestionIcon() Messages.getQuestionIcon()
) )
if (answer != Messages.YES) return }
if (answer != Messages.YES) {
return
}
var showAll = false var showAll = false
@@ -113,8 +119,8 @@ fun processDuplicates(
} }
} }
} }
highlighter?.let { HighlightManager.getInstance(project).removeSegmentHighlighter(editor, it) }
highlighter?.let { HighlightManager.getInstance(project).removeSegmentHighlighter(editor, it) }
project.executeWriteCommand(MethodDuplicatesHandler.REFACTORING_NAME, replacer) project.executeWriteCommand(MethodDuplicatesHandler.REFACTORING_NAME, replacer)
} }
} }
@@ -75,8 +75,9 @@ import java.util.*
internal val KotlinBuiltIns.defaultReturnType: KotlinType get() = unitType internal val KotlinBuiltIns.defaultReturnType: KotlinType get() = unitType
internal val KotlinBuiltIns.defaultParameterType: KotlinType get() = nullableAnyType internal val KotlinBuiltIns.defaultParameterType: KotlinType get() = nullableAnyType
private fun DeclarationDescriptor.renderForMessage(): String = private fun DeclarationDescriptor.renderForMessage(): String {
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.render(this) return IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.render(this)
}
private val TYPE_RENDERER = DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { private val TYPE_RENDERER = DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions {
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
@@ -87,8 +88,6 @@ private fun KotlinType.renderForMessage(): String = TYPE_RENDERER.renderType(thi
private fun KtDeclaration.renderForMessage(bindingContext: BindingContext): String? = private fun KtDeclaration.renderForMessage(bindingContext: BindingContext): String? =
bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this]?.renderForMessage() bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this]?.renderForMessage()
internal fun KotlinType.isDefault(): Boolean = KotlinBuiltIns.isUnit(this)
private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingContext): Map<VariableDescriptor, List<KtExpression>> { private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingContext): Map<VariableDescriptor, List<KtExpression>> {
val result = HashMap<VariableDescriptor, MutableList<KtExpression>>() val result = HashMap<VariableDescriptor, MutableList<KtExpression>>()
for (instruction in filterIsInstance<WriteValueInstruction>()) { for (instruction in filterIsInstance<WriteValueInstruction>()) {
@@ -160,7 +159,8 @@ private fun ExtractionData.getResultTypeAndExpressions(
val resultTypes = instructions.mapNotNull(::instructionToType) val resultTypes = instructions.mapNotNull(::instructionToType)
val commonSupertype = if (resultTypes.isNotEmpty()) CommonSupertypes.commonSupertype(resultTypes) else module.builtIns.defaultReturnType val commonSupertype = if (resultTypes.isNotEmpty()) CommonSupertypes.commonSupertype(resultTypes) else module.builtIns.defaultReturnType
val resultType = if (options.allowSpecialClassNames) commonSupertype else commonSupertype.approximateWithResolvableType(targetScope, false) val resultType =
if (options.allowSpecialClassNames) commonSupertype else commonSupertype.approximateWithResolvableType(targetScope, false)
val expressions = instructions.mapNotNull { instructionToExpression(it, false) } val expressions = instructions.mapNotNull { instructionToExpression(it, false) }
@@ -257,8 +257,7 @@ private fun ExtractionData.analyzeControlFlow(
if (inst.owner == pseudocode) { if (inst.owner == pseudocode) {
if (inst.returnExpressionIfAny == null) { if (inst.returnExpressionIfAny == null) {
defaultExits.add(inst) defaultExits.add(inst)
} } else {
else {
valuedReturnExits.add(inst) valuedReturnExits.add(inst)
} }
} }
@@ -268,10 +267,10 @@ private fun ExtractionData.analyzeControlFlow(
val element = inst.element val element = inst.element
if ((element is KtReturnExpression && inst.owner == pseudocode) if ((element is KtReturnExpression && inst.owner == pseudocode)
|| element is KtBreakExpression || element is KtBreakExpression
|| element is KtContinueExpression) { || element is KtContinueExpression
) {
jumpExits.add(inst) jumpExits.add(inst)
} } else if (element !is KtThrowExpression && !inst.targetLabel.isJumpToError) {
else if (element !is KtThrowExpression && !inst.targetLabel.isJumpToError) {
defaultExits.add(inst) defaultExits.add(inst)
} }
} }
@@ -285,8 +284,21 @@ private fun ExtractionData.analyzeControlFlow(
val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext) val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)
val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is KtProperty && it.isLocal } val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is KtProperty && it.isLocal }
val (typeOfDefaultFlow, defaultResultExpressions) = getResultTypeAndExpressions(defaultExits, bindingContext, targetScope, options, module) val (typeOfDefaultFlow, defaultResultExpressions) = getResultTypeAndExpressions(
val (returnValueType, valuedReturnExpressions) = getResultTypeAndExpressions(valuedReturnExits, bindingContext, targetScope, options, module) defaultExits,
bindingContext,
targetScope,
options,
module
)
val (returnValueType, valuedReturnExpressions) = getResultTypeAndExpressions(
valuedReturnExits,
bindingContext,
targetScope,
options,
module
)
val emptyControlFlow = val emptyControlFlow =
ControlFlow(Collections.emptyList(), { OutputValueBoxer.AsTuple(it, module) }, declarationsToCopy) ControlFlow(Collections.emptyList(), { OutputValueBoxer.AsTuple(it, module) }, declarationsToCopy)
@@ -296,8 +308,7 @@ private fun ExtractionData.analyzeControlFlow(
val controlFlow = if (defaultReturnType.isMeaningful()) { val controlFlow = if (defaultReturnType.isMeaningful()) {
emptyControlFlow.copy(outputValues = Collections.singletonList(ExpressionValue(false, defaultResultExpressions, defaultReturnType))) emptyControlFlow.copy(outputValues = Collections.singletonList(ExpressionValue(false, defaultResultExpressions, defaultReturnType)))
} } else {
else {
emptyControlFlow emptyControlFlow
} }
@@ -321,8 +332,7 @@ private fun ExtractionData.analyzeControlFlow(
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
outputValues.add(ExpressionValue(false, defaultResultExpressions, typeOfDefaultFlow)) outputValues.add(ExpressionValue(false, defaultResultExpressions, typeOfDefaultFlow))
} } else if (valuedReturnExits.isNotEmpty()) {
else if (valuedReturnExits.isNotEmpty()) {
if (jumpExits.isNotEmpty()) return multipleExitsError if (jumpExits.isNotEmpty()) return multipleExitsError
if (defaultExits.isNotEmpty()) { if (defaultExits.isNotEmpty()) {
@@ -354,7 +364,7 @@ private fun ExtractionData.analyzeControlFlow(
+ outDeclarations.map { it.renderForMessage(bindingContext)!! }).sorted() + outDeclarations.map { it.renderForMessage(bindingContext)!! }).sorted()
return controlFlow to ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr) return controlFlow to ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr)
} }
{ outputValues -> OutputValueBoxer.AsList(outputValues) } // KT-8596 { values -> OutputValueBoxer.AsList(values) }
} }
else -> controlFlow.boxerFactory else -> controlFlow.boxerFactory
@@ -370,7 +380,16 @@ private fun ExtractionData.analyzeControlFlow(
val conditional = !singleExit && defaultExits.isNotEmpty() val conditional = !singleExit && defaultExits.isNotEmpty()
val elements = jumpExits.map { it.element as KtExpression } val elements = jumpExits.map { it.element as KtExpression }
val elementToInsertAfterCall = if (singleExit) null else elements.first() val elementToInsertAfterCall = if (singleExit) null else elements.first()
return controlFlow.copy(outputValues = Collections.singletonList(Jump(elements, elementToInsertAfterCall, conditional, module.builtIns))) to null return controlFlow.copy(
outputValues = Collections.singletonList(
Jump(
elements,
elementToInsertAfterCall,
conditional,
module.builtIns
)
)
) to null
} }
return controlFlow to null return controlFlow to null
@@ -391,8 +410,7 @@ fun ExtractionData.createTemporaryDeclaration(pattern: String): KtNamedDeclarati
) )
return if (insertBefore) { return if (insertBefore) {
newTargetParent.addBefore(declaration, newTargetSibling) as KtNamedDeclaration newTargetParent.addBefore(declaration, newTargetSibling) as KtNamedDeclaration
} } else {
else {
newTargetParent.addAfter(declaration, newTargetSibling) as KtNamedDeclaration newTargetParent.addAfter(declaration, newTargetSibling) as KtNamedDeclaration
} }
} }
@@ -515,8 +533,7 @@ internal class MutableParameter(
writable = false writable = false
if (defaultTypes.isNotEmpty()) { if (defaultTypes.isNotEmpty()) {
TypeIntersector.intersectTypes(defaultTypes)!! TypeIntersector.intersectTypes(defaultTypes)!!
} } else originalType
else originalType
} }
private val parameterTypeCandidates: List<KotlinType> by lazy { private val parameterTypeCandidates: List<KotlinType> by lazy {
@@ -530,8 +547,7 @@ internal class MutableParameter(
if (typePredicate(bounds.upperBound)) add(bounds.upperBound) if (typePredicate(bounds.upperBound)) add(bounds.upperBound)
if (typePredicate(bounds.lowerBound)) add(bounds.lowerBound) if (typePredicate(bounds.lowerBound)) add(bounds.lowerBound)
} }
} } else linkedSetOf(defaultType)
else linkedSetOf(defaultType)
val addNullableTypes = defaultType.isNullabilityFlexible() && typeSet.size > 1 val addNullableTypes = defaultType.isNullabilityFlexible() && typeSet.size > 1
val superTypes = TypeUtils.getAllSupertypes(defaultType).filter(typePredicate) val superTypes = TypeUtils.getAllSupertypes(defaultType).filter(typePredicate)
@@ -582,7 +598,8 @@ private fun ExtractionData.checkDeclarationsMovingOutOfScope(
val target = expression.mainReference.resolve() val target = expression.mainReference.resolve()
if (target is KtNamedDeclaration if (target is KtNamedDeclaration
&& target.isInsideOf(physicalElements) && target.isInsideOf(physicalElements)
&& target.getStrictParentOfType<KtDeclaration>() == enclosingDeclaration) { && target.getStrictParentOfType<KtDeclaration>() == enclosingDeclaration
) {
declarationsOutOfScope.add(target) declarationsOutOfScope.add(target)
} }
} }
@@ -700,7 +717,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
) )
val adjustedParameters = paramsInfo.parameters.filterTo(LinkedHashSet<Parameter>()) { it.refCount > 0 } val adjustedParameters = paramsInfo.parameters.filterTo(LinkedHashSet<Parameter>()) { it.refCount > 0 }
val receiverCandidates = adjustedParameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate } val receiverCandidates = adjustedParameters.filterTo(hashSetOf()) { it.receiverCandidate }
val receiverParameter = if (receiverCandidates.size == 1 && !options.canWrapInWith) receiverCandidates.first() else null val receiverParameter = if (receiverCandidates.size == 1 && !options.canWrapInWith) receiverCandidates.first() else null
receiverParameter?.let { adjustedParameters.remove(it) } receiverParameter?.let { adjustedParameters.remove(it) }
@@ -744,7 +761,7 @@ private fun ExtractionData.suggestFunctionNames(returnType: KotlinType): List<St
if (targetSibling is KtAnonymousInitializer) targetSibling.parent else targetSibling, if (targetSibling is KtAnonymousInitializer) targetSibling.parent else targetSibling,
if (options.extractAsProperty) NewDeclarationNameValidator.Target.VARIABLES else NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES if (options.extractAsProperty) NewDeclarationNameValidator.Target.VARIABLES else NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES
) )
if (!returnType.isDefault()) { if (!KotlinBuiltIns.isUnit(returnType)) {
functionNames.addAll(KotlinNameSuggester.suggestNamesByType(returnType, validator)) functionNames.addAll(KotlinNameSuggester.suggestNamesByType(returnType, validator))
} }
@@ -806,7 +823,8 @@ fun ExtractableCodeDescriptor.validate(target: ExtractionTarget = ExtractionTarg
if (currentTarget is KtParameter && currentTarget.parent == valueParameterList) return if (currentTarget is KtParameter && currentTarget.parent == valueParameterList) return
if (currentTarget is KtTypeParameter && currentTarget.parent == typeParameterList) return if (currentTarget is KtTypeParameter && currentTarget.parent == typeParameterList) return
if (currentDescriptor is LocalVariableDescriptor if (currentDescriptor is LocalVariableDescriptor
&& parameters.any { it.mirrorVarName == currentDescriptor.name.asString() }) return && parameters.any { it.mirrorVarName == currentDescriptor.name.asString() }
) return
if (diagnostics.any { it.factory in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS } if (diagnostics.any { it.factory in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS }
|| (currentDescriptor != null || (currentDescriptor != null
@@ -849,5 +867,3 @@ fun ExtractableCodeDescriptor.validate(target: ExtractionTarget = ExtractionTarg
return ExtractableCodeDescriptorWithConflicts(this, conflicts) return ExtractableCodeDescriptorWithConflicts(this, conflicts)
} }
private val LOG = Logger.getInstance(ExtractionEngine::class.java)
@@ -24,6 +24,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.BaseRefactoringProcessor import com.intellij.refactoring.BaseRefactoringProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -116,12 +117,14 @@ private fun buildSignature(config: ExtractionGeneratorConfiguration, renderer: D
name(config.generatorOptions.dummyName ?: config.descriptor.name) name(config.generatorOptions.dummyName ?: config.descriptor.name)
config.descriptor.parameters.forEach { parameter -> config.descriptor.parameters.forEach { parameter ->
param(parameter.name, param(
parameter.getParameterType(config.descriptor.extractionData.options.allowSpecialClassNames).typeAsString()) parameter.name,
parameter.getParameterType(config.descriptor.extractionData.options.allowSpecialClassNames).typeAsString()
)
} }
with(config.descriptor.returnType) { with(config.descriptor.returnType) {
if (isDefault() || isError || extractionTarget == ExtractionTarget.PROPERTY_WITH_INITIALIZER) { if (KotlinBuiltIns.isUnit(this) || isError || extractionTarget == ExtractionTarget.PROPERTY_WITH_INITIALIZER) {
noReturnType() noReturnType()
} else { } else {
returnType(typeAsString()) returnType(typeAsString())
@@ -225,7 +228,8 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
return if (matched) newControlFlow else null return if (matched) newControlFlow else null
} }
val unifierParameters = parameters.map { UnifierParameter(it.originalDescriptor, it.getParameterType(extractionData.options.allowSpecialClassNames)) } val unifierParameters =
parameters.map { UnifierParameter(it.originalDescriptor, it.getParameterType(extractionData.options.allowSpecialClassNames)) }
val unifier = KotlinPsiUnifier(unifierParameters, true) val unifier = KotlinPsiUnifier(unifierParameters, true)
@@ -241,7 +245,12 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
val range = with(match.range) { val range = with(match.range) {
(elements.singleOrNull() as? KtStringTemplateEntryWithExpression)?.expression?.toRange() ?: this (elements.singleOrNull() as? KtStringTemplateEntryWithExpression)?.expression?.toRange() ?: this
} }
controlFlow?.let { DuplicateInfo(range, it, unifierParameters.map { match.substitution[it]!!.text!! }) }
controlFlow?.let {
DuplicateInfo(range, it, unifierParameters.map { param ->
match.substitution[param]!!.text!!
})
}
} }
.toList() .toList()
} }
@@ -255,7 +264,8 @@ private fun makeCall(
declaration: KtNamedDeclaration, declaration: KtNamedDeclaration,
controlFlow: ControlFlow, controlFlow: ControlFlow,
rangeToReplace: KotlinPsiRange, rangeToReplace: KotlinPsiRange,
arguments: List<String>) { arguments: List<String>
) {
fun insertCall(anchor: PsiElement, wrappedCall: KtExpression): KtExpression? { fun insertCall(anchor: PsiElement, wrappedCall: KtExpression): KtExpression? {
val firstExpression = rangeToReplace.elements.firstOrNull { it is KtExpression } as? KtExpression val firstExpression = rangeToReplace.elements.firstOrNull { it is KtExpression } as? KtExpression
if (firstExpression?.isLambdaOutsideParentheses() ?: false) { if (firstExpression?.isLambdaOutsideParentheses() ?: false) {
@@ -318,7 +328,7 @@ private fun makeCall(
val isVar = declarationsToMerge.first().isVar val isVar = declarationsToMerge.first().isVar
if (declarationsToMerge.all { it.isVar == isVar }) { if (declarationsToMerge.all { it.isVar == isVar }) {
controlFlow.declarationsToCopy.subtract(declarationsToMerge).forEach { controlFlow.declarationsToCopy.subtract(declarationsToMerge).forEach {
block.addBefore(psiFactory.createDeclaration<KtDeclaration>(it.text!!), anchorInBlock) as KtDeclaration block.addBefore(psiFactory.createDeclaration(it.text!!), anchorInBlock) as KtDeclaration
block.addBefore(newLine, anchorInBlock) block.addBefore(newLine, anchorInBlock)
} }
@@ -335,8 +345,7 @@ private fun makeCall(
val unboxingExpressions = val unboxingExpressions =
if (inlinableCall) { if (inlinableCall) {
controlFlow.outputValueBoxer.getUnboxingExpressions(callText ?: return) controlFlow.outputValueBoxer.getUnboxingExpressions(callText ?: return)
} } else {
else {
val varNameValidator = NewDeclarationNameValidator(block, anchorInBlock, NewDeclarationNameValidator.Target.VARIABLES) val varNameValidator = NewDeclarationNameValidator(block, anchorInBlock, NewDeclarationNameValidator.Target.VARIABLES)
val resultVal = KotlinNameSuggester.suggestNamesByType(extractableDescriptor.returnType, varNameValidator, null).first() val resultVal = KotlinNameSuggester.suggestNamesByType(extractableDescriptor.returnType, varNameValidator, null).first()
block.addBefore(psiFactory.createDeclaration("val $resultVal = $callText"), anchorInBlock) block.addBefore(psiFactory.createDeclaration("val $resultVal = $callText"), anchorInBlock)
@@ -363,8 +372,7 @@ private fun makeCall(
val firstReturn = outputValue.originalExpressions.asSequence().filterIsInstance<KtReturnExpression>().firstOrNull() val firstReturn = outputValue.originalExpressions.asSequence().filterIsInstance<KtReturnExpression>().firstOrNull()
val label = firstReturn?.getTargetLabel()?.text ?: "" val label = firstReturn?.getTargetLabel()?.text ?: ""
"return$label $callText" "return$label $callText"
} } else {
else {
callText callText
} }
Collections.singletonList(psiFactory.createExpression(exprText)) Collections.singletonList(psiFactory.createExpression(exprText))
@@ -438,7 +446,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val psiFactory = KtPsiFactory(descriptor.extractionData.originalFile) val psiFactory = KtPsiFactory(descriptor.extractionData.originalFile)
fun getReturnsForLabelRemoval() = descriptor.controlFlow.outputValues fun getReturnsForLabelRemoval() = descriptor.controlFlow.outputValues
.flatMapTo(ArrayList<KtReturnExpression>()) { it.originalExpressions.filterIsInstance<KtReturnExpression>() } .flatMapTo(arrayListOf()) { it.originalExpressions.filterIsInstance<KtReturnExpression>() }
fun createDeclaration(): KtNamedDeclaration { fun createDeclaration(): KtNamedDeclaration {
descriptor.controlFlow.jumpOutputValue?.elementsToReplace?.forEach { it.isJumpElementToReplace = true } descriptor.controlFlow.jumpOutputValue?.elementsToReplace?.forEach { it.isJumpElementToReplace = true }
@@ -447,8 +455,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
return with(descriptor.extractionData) { return with(descriptor.extractionData) {
if (generatorOptions.inTempFile) { if (generatorOptions.inTempFile) {
createTemporaryDeclaration("${getDeclarationPattern()}\n") createTemporaryDeclaration("${getDeclarationPattern()}\n")
} } else {
else {
psiFactory.createDeclarationByPattern( psiFactory.createDeclarationByPattern(
getDeclarationPattern(), getDeclarationPattern(),
PsiChildRange(originalElements.firstOrNull(), originalElements.lastOrNull()) PsiChildRange(originalElements.firstOrNull(), originalElements.lastOrNull())
@@ -535,9 +542,8 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val resolveResult = it.resolveResult!! val resolveResult = it.resolveResult!!
val currentRef = if (it.isValid) { val currentRef = if (it.isValid) {
it it
} } else {
else { body.findDescendantOfType { expr -> expr.resolveResult == resolveResult } ?: return@forEach
body.findDescendantOfType<KtSimpleNameExpression> { it.resolveResult == resolveResult } ?: return@forEach
} }
val originalRef = resolveResult.originalRefExpr val originalRef = resolveResult.originalRefExpr
val newRef = descriptor.replacementMap[originalRef] val newRef = descriptor.replacementMap[originalRef]
@@ -571,10 +577,10 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
body.addBefore(psiFactory.createDeclaration("val $resultVal = ${lastExpression.text}"), lastExpression) body.addBefore(psiFactory.createDeclaration("val $resultVal = ${lastExpression.text}"), lastExpression)
body.addBefore(psiFactory.createNewLine(), lastExpression) body.addBefore(psiFactory.createNewLine(), lastExpression)
psiFactory.createExpression(resultVal) psiFactory.createExpression(resultVal)
} } else lastExpression
else lastExpression
val returnExpression = descriptor.controlFlow.outputValueBoxer.getReturnExpression(getReturnArguments(defaultExpression), psiFactory) ?: return val returnExpression =
descriptor.controlFlow.outputValueBoxer.getReturnExpression(getReturnArguments(defaultExpression), psiFactory) ?: return
@Suppress("NON_EXHAUSTIVE_WHEN") @Suppress("NON_EXHAUSTIVE_WHEN")
when (generatorOptions.target) { when (generatorOptions.target) {
@@ -614,8 +620,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
(targetContainer.addBefore(declaration, anchor) as KtNamedDeclaration).apply { (targetContainer.addBefore(declaration, anchor) as KtNamedDeclaration).apply {
targetContainer.addBefore(emptyLines, anchor) targetContainer.addBefore(emptyLines, anchor)
} }
} } else {
else {
(targetContainer.addAfter(declaration, anchor) as KtNamedDeclaration).apply { (targetContainer.addAfter(declaration, anchor) as KtNamedDeclaration).apply {
if (!(targetContainer is KtClassBody && (targetContainer.parent as? KtClass)?.isEnum() ?: false)) { if (!(targetContainer is KtClassBody && (targetContainer.parent as? KtClass)?.isEnum() ?: false)) {
targetContainer.addAfter(emptyLines, anchor) targetContainer.addAfter(emptyLines, anchor)
@@ -630,7 +635,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val anchor = with(descriptor.extractionData) { val anchor = with(descriptor.extractionData) {
val targetParent = targetSibling.parent val targetParent = targetSibling.parent
val anchorCandidates = duplicates.mapTo(ArrayList<PsiElement>()) { it.range.elements.first().substringContextOrThis } val anchorCandidates = duplicates.mapTo(arrayListOf()) { it.range.elements.first().substringContextOrThis }
anchorCandidates.add(targetSibling) anchorCandidates.add(targetSibling)
if (targetSibling is KtEnumEntry) { if (targetSibling is KtEnumEntry) {
anchorCandidates.add(targetSibling.siblings().last { it is KtEnumEntry }) anchorCandidates.add(targetSibling.siblings().last { it is KtEnumEntry })
@@ -638,8 +643,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val marginalCandidate = if (insertBefore) { val marginalCandidate = if (insertBefore) {
anchorCandidates.minBy { it.startOffset }!! anchorCandidates.minBy { it.startOffset }!!
} } else {
else {
anchorCandidates.maxBy { it.startOffset }!! anchorCandidates.maxBy { it.startOffset }!!
} }
@@ -95,8 +95,7 @@ internal fun ExtractionData.inferParametersInfo(
val extensionReceiver = resolvedCall?.extensionReceiver val extensionReceiver = resolvedCall?.extensionReceiver
val receiverToExtract = (if (extensionReceiver == null || isSynthesizedInvoke(refInfo.resolveResult.descriptor)) { val receiverToExtract = (if (extensionReceiver == null || isSynthesizedInvoke(refInfo.resolveResult.descriptor)) {
resolvedCall?.dispatchReceiver resolvedCall?.dispatchReceiver
} } else {
else {
extensionReceiver extensionReceiver
}) })
@@ -105,18 +104,39 @@ internal fun ExtractionData.inferParametersInfo(
if (options.canWrapInWith if (options.canWrapInWith
&& twoReceivers && twoReceivers
&& resolvedCall!!.extensionReceiver is ExpressionReceiver && resolvedCall!!.extensionReceiver is ExpressionReceiver
&& DescriptorUtils.isObject(dispatchReceiverDescriptor)) { && DescriptorUtils.isObject(dispatchReceiverDescriptor)
info.replacementMap.putValue(refInfo.resolveResult.originalRefExpr, ) {
WrapObjectInWithReplacement(dispatchReceiverDescriptor as ClassDescriptor)) info.replacementMap.putValue(
refInfo.resolveResult.originalRefExpr,
WrapObjectInWithReplacement(dispatchReceiverDescriptor as ClassDescriptor)
)
continue continue
} }
if (!refInfo.shouldSkipPrimaryReceiver) { if (!refInfo.shouldSkipPrimaryReceiver) {
extractReceiver(receiverToExtract, info, targetScope, refInfo, extractedDescriptorToParameter, pseudocode, bindingContext, false) extractReceiver(
receiverToExtract,
info,
targetScope,
refInfo,
extractedDescriptorToParameter,
pseudocode,
bindingContext,
false
)
} }
if (options.canWrapInWith && twoReceivers) { if (options.canWrapInWith && twoReceivers) {
extractReceiver(resolvedCall!!.dispatchReceiver, info, targetScope, refInfo, extractedDescriptorToParameter, pseudocode, bindingContext, true) extractReceiver(
resolvedCall!!.dispatchReceiver,
info,
targetScope,
refInfo,
extractedDescriptorToParameter,
pseudocode,
bindingContext,
true
)
} }
} }
@@ -130,11 +150,14 @@ internal fun ExtractionData.inferParametersInfo(
for ((descriptorToExtract, parameter) in extractedDescriptorToParameter) { for ((descriptorToExtract, parameter) in extractedDescriptorToParameter) {
if (!parameter if (!parameter
.getParameterType(options.allowSpecialClassNames) .getParameterType(options.allowSpecialClassNames)
.processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes, options, targetScope)) continue .processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes, options, targetScope)
) continue
with(parameter) { with(parameter) {
if (currentName == null) { if (currentName == null) {
currentName = KotlinNameSuggester.suggestNamesByType(getParameterType(options.allowSpecialClassNames), varNameValidator, "p").first() currentName =
KotlinNameSuggester.suggestNamesByType(getParameterType(options.allowSpecialClassNames), varNameValidator, "p")
.first()
} }
require(currentName != null) require(currentName != null)
@@ -147,7 +170,10 @@ internal fun ExtractionData.inferParametersInfo(
currentName = "$currentName$index" currentName = "$currentName$index"
} }
mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) KotlinNameSuggester.suggestNameByName(name, varNameValidator) else null mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) KotlinNameSuggester.suggestNameByName(
name,
varNameValidator
) else null
info.parameters.add(this) info.parameters.add(this)
currentName?.let { existingParameterNames += it } currentName?.let { existingParameterNames += it }
} }
@@ -178,7 +204,8 @@ private fun ExtractionData.extractReceiver(
val thisExpr = refInfo.refExpr.parent as? KtThisExpression val thisExpr = refInfo.refExpr.parent as? KtThisExpression
if (hasThisReceiver if (hasThisReceiver
&& DescriptorToSourceUtilsIde.getAllDeclarations(project, thisDescriptor!!).all { it.isInsideOf(physicalElements) }) { && DescriptorToSourceUtilsIde.getAllDeclarations(project, thisDescriptor!!).all { it.isInsideOf(physicalElements) }
) {
return return
} }
@@ -202,18 +229,19 @@ private fun ExtractionData.extractReceiver(
if (referencedClassifierDescriptor != null) { if (referencedClassifierDescriptor != null) {
if (!referencedClassifierDescriptor.defaultType.processTypeIfExtractable( if (!referencedClassifierDescriptor.defaultType.processTypeIfExtractable(
info.typeParameters, info.nonDenotableTypes, options, targetScope, referencedClassifierDescriptor is TypeParameterDescriptor info.typeParameters, info.nonDenotableTypes, options, targetScope, referencedClassifierDescriptor is TypeParameterDescriptor
)) return )
) return
if (options.canWrapInWith if (options.canWrapInWith
&& resolvedCall != null && resolvedCall != null
&& resolvedCall.hasBothReceivers() && resolvedCall.hasBothReceivers()
&& DescriptorUtils.isObject(referencedClassifierDescriptor)) { && DescriptorUtils.isObject(referencedClassifierDescriptor)
) {
info.replacementMap.putValue(originalRef, WrapObjectInWithReplacement(referencedClassifierDescriptor as ClassDescriptor)) info.replacementMap.putValue(originalRef, WrapObjectInWithReplacement(referencedClassifierDescriptor as ClassDescriptor))
} else if (referencedClassifierDescriptor is ClassDescriptor) { } else if (referencedClassifierDescriptor is ClassDescriptor) {
info.replacementMap.putValue(originalRef, FqNameReplacement(originalDescriptor.getImportableDescriptor().fqNameSafe)) info.replacementMap.putValue(originalRef, FqNameReplacement(originalDescriptor.getImportableDescriptor().fqNameSafe))
} }
} } else {
else {
val extractThis = (hasThisReceiver && refInfo.smartCast == null) || thisExpr != null val extractThis = (hasThisReceiver && refInfo.smartCast == null) || thisExpr != null
val extractOrdinaryParameter = val extractOrdinaryParameter =
originalDeclaration is KtDestructuringDeclarationEntry || originalDeclaration is KtDestructuringDeclarationEntry ||
@@ -240,15 +268,22 @@ private fun ExtractionData.extractReceiver(
else -> (originalRef.parent as? KtThisExpression) ?: originalRef else -> (originalRef.parent as? KtThisExpression) ?: originalRef
} }
val parameterType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, true, bindingContext) val parameterType = suggestParameterType(
extractFunctionRef,
originalDescriptor,
parameterExpression,
receiverToExtract,
resolvedCall,
true,
bindingContext
)
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) { val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
var argumentText = var argumentText =
if (hasThisReceiver && extractThis) { if (hasThisReceiver && extractThis) {
val label = if (descriptorToExtract is ClassDescriptor) "@${descriptorToExtract.name.asString()}" else "" val label = if (descriptorToExtract is ClassDescriptor) "@${descriptorToExtract.name.asString()}" else ""
"this$label" "this$label"
} } else {
else {
val argumentExpr = (thisExpr ?: refInfo.refExpr).getQualifiedExpressionForSelectorOrThis() val argumentExpr = (thisExpr ?: refInfo.refExpr).getQualifiedExpressionForSelectorOrThis()
if (argumentExpr is KtOperationReferenceExpression) { if (argumentExpr is KtOperationReferenceExpression) {
val nameElement = argumentExpr.getReferencedNameElement() val nameElement = argumentExpr.getReferencedNameElement()
@@ -256,8 +291,7 @@ private fun ExtractionData.extractReceiver(
(nameElementType as? KtToken)?.let { (nameElementType as? KtToken)?.let {
OperatorConventions.getNameForOperationSymbol(it)?.asString() OperatorConventions.getNameForOperationSymbol(it)?.asString()
} ?: nameElement.text } ?: nameElement.text
} } else argumentExpr.text
else argumentExpr.text
?: throw AssertionError("reference shouldn't be empty: code fragment = $codeFragmentText") ?: throw AssertionError("reference shouldn't be empty: code fragment = $codeFragmentText")
} }
if (extractFunctionRef) { if (extractFunctionRef) {
@@ -265,7 +299,15 @@ private fun ExtractionData.extractReceiver(
argumentText = "$receiverTypeText::$argumentText" argumentText = "$receiverTypeText::$argumentText"
} }
val originalType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, false, bindingContext) val originalType = suggestParameterType(
extractFunctionRef,
originalDescriptor,
parameterExpression,
receiverToExtract,
resolvedCall,
false,
bindingContext
)
MutableParameter(argumentText, descriptorToExtract, extractThis, targetScope, originalType, refInfo.possibleTypes) MutableParameter(argumentText, descriptorToExtract, extractThis, targetScope, originalType, refInfo.possibleTypes)
} }
@@ -287,13 +329,17 @@ private fun ExtractionData.extractReceiver(
val instruction = pseudocode.getElementValue(callElement)?.createdAt as? InstructionWithReceivers val instruction = pseudocode.getElementValue(callElement)?.createdAt as? InstructionWithReceivers
val receiverValue = instruction?.receiverValues?.entries?.singleOrNull { it.value == receiverToExtract }?.key val receiverValue = instruction?.receiverValues?.entries?.singleOrNull { it.value == receiverToExtract }?.key
if (receiverValue != null) { if (receiverValue != null) {
parameter.addTypePredicate(getExpectedTypePredicate(receiverValue, bindingContext, targetScope.ownerDescriptor.builtIns)) parameter.addTypePredicate(
getExpectedTypePredicate(
receiverValue,
bindingContext,
targetScope.ownerDescriptor.builtIns
)
)
} }
} } else if (extractFunctionRef) {
else if (extractFunctionRef) {
parameter.addTypePredicate(SingleType(parameterType)) parameter.addTypePredicate(SingleType(parameterType))
} } else {
else {
pseudocode.getElementValuesRecursively(originalRef).forEach { pseudocode.getElementValuesRecursively(originalRef).forEach {
parameter.addTypePredicate(getExpectedTypePredicate(it, bindingContext, targetScope.ownerDescriptor.builtIns)) parameter.addTypePredicate(getExpectedTypePredicate(it, bindingContext, targetScope.ownerDescriptor.builtIns))
} }