Minor: Reformat extraction engine files
This commit is contained in:
+12
-9
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-16
@@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -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)
|
||||||
|
|||||||
+18
-12
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-30
@@ -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)
|
|
||||||
|
|||||||
+29
-25
@@ -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 }!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+72
-26
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user