fun modifyExternalParameters()

in src/main/kotlin/org/arend/refactoring/changeSignature/ArendChangeSignatureUtils.kt [30:106]


fun modifyExternalParameters(oldParameters: List<ParameterDescriptor>,
                             newParameters: List<ParameterDescriptor>,
                             affectedDefinition: PsiReferable,
                             affectedDefinitionOldParameters: List<ParameterDescriptor>): ChangeSignatureRefactoringDescriptor? {
    val relevantParameters = oldParameters.filter { !it.isExternal() && it.getReferable() != null }.map { it.getReferable() }.toSet()
    var relevantSegmentStartIndex = -1
    var relevantSegmentEndIndex = -1
    var externalSegmentEndIndex = -1

    for ((index, parameter) in affectedDefinitionOldParameters.withIndex()) {
        if (parameter.isExternal()) {
            if (relevantParameters.contains(parameter.getReferable())) {
                if (relevantSegmentStartIndex == -1) relevantSegmentStartIndex = index
                continue
            }
        } else {
            if (externalSegmentEndIndex == -1) externalSegmentEndIndex = index
        }

        if (relevantSegmentStartIndex != -1) {
            if (relevantSegmentEndIndex == -1) relevantSegmentEndIndex = index
        }
    }

    if (relevantSegmentEndIndex == -1) {
        if (relevantSegmentStartIndex == -1) return null
        relevantSegmentEndIndex = affectedDefinitionOldParameters.size
    }
    if (externalSegmentEndIndex == -1) {
        externalSegmentEndIndex = affectedDefinitionOldParameters.size
    }

    val relevantReferables = LinkedHashMap<PsiElement, ParameterDescriptor>()

    affectedDefinitionOldParameters.subList(relevantSegmentStartIndex, relevantSegmentEndIndex).forEach {
        relevantReferables[it.getReferable()!!] = it
    }
    val newRelevantSegment = ArrayList<ParameterDescriptor>()
    val internalizedSegment = ArrayList<ParameterDescriptor>()

    for (parameter in newParameters) if (parameter.oldParameter != null) {
        val oldReferable = parameter.oldParameter.getReferable()!!
        if (relevantReferables.keys.contains(oldReferable)) {
            val oldParameter = relevantReferables[oldReferable]!!
            val isData = oldParameter.isDataParameter
            val newParameter = if (isData)
                DefaultParameterDescriptorFactory.createDataParameter(oldParameter, oldParameter.getExternalScope(), parameter.getNameOrNull(), parameter.typeGetter, oldReferable as? PsiReferable) else
                DefaultParameterDescriptorFactory.createNewParameter(false, oldParameter, oldParameter.getExternalScope(), parameter.getNameOrNull(), parameter.typeGetter)
            newRelevantSegment.add(newParameter)
            relevantReferables.remove(oldReferable)
        }
    }

    for (entry in relevantReferables) {
        val isData = entry.value.isDataParameter
        val newParameter = if (isData)
            DefaultParameterDescriptorFactory.createDataParameter(entry.value, null, null, entry.value.typeGetter, entry.value.oldParameter?.getReferable() as? PsiReferable) else
            DefaultParameterDescriptorFactory.createNewParameter(entry.value.isExplicit, entry.value, null, null, entry.value.typeGetter)
        internalizedSegment.add(newParameter)
    }

    val headExternalSegment = affectedDefinitionOldParameters.subList(0, relevantSegmentStartIndex)
    assert (relevantSegmentEndIndex <= externalSegmentEndIndex)
    val tailExternalSegment = affectedDefinitionOldParameters.subList(relevantSegmentEndIndex, externalSegmentEndIndex)
    val internalSegment = affectedDefinitionOldParameters.subList(externalSegmentEndIndex, affectedDefinitionOldParameters.size)

    val definitionNewSignature =
        DefaultParameterDescriptorFactory.identityTransform(headExternalSegment) +
                newRelevantSegment +
                DefaultParameterDescriptorFactory.identityTransform(tailExternalSegment) +
                internalizedSegment +
                DefaultParameterDescriptorFactory.identityTransform(internalSegment)

    val descriptor = ChangeSignatureRefactoringDescriptor(affectedDefinition, affectedDefinitionOldParameters, definitionNewSignature, null)

    return if (descriptor.isTrivial()) null else descriptor
}