<commit_before>/*
 * Use of this source code is governed by the MIT license that can be
 * found in the LICENSE file.
 */

package org.rust.ide.presentation

import com.intellij.ide.projectView.PresentationData
import com.intellij.navigation.ItemPresentation
import com.intellij.openapi.util.text.StringUtil
import org.rust.ide.icons.addVisibilityIcon
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.*
import org.rust.lang.core.types.type


fun getPresentation(psi: RsElement): ItemPresentation {
    val location = run {
        val mod = psi.containingMod
        "(in ${mod.qualifiedName ?: mod.modName ?: psi.containingFile.name})"
    }

    val name = presentableName(psi)
    return PresentationData(name, location, psi.getIcon(0), null)
}

fun getPresentationForStructure(psi: RsElement): ItemPresentation {
    val presentation = buildString {
        fun appendCommaList(xs: List<String>) {
            append('(')
            append(xs.joinToString(", "))
            append(')')
        }
        append(presentableName(psi))
        when (psi) {
            is RsFunction -> {
                appendCommaList(psi.valueParameters.mapNotNull { it.typeReference?.text })

                val ret = psi.retType?.typeReference
                if (ret != null) append(" -> ${ret.text}")
            }
            is RsConstant -> {
                psi.typeReference?.let { append(": ${it.text}") }
            }
            is RsFieldDecl -> {
                psi.typeReference?.let { append(": ${it.text}") }
            }
            is RsEnumVariant -> {
                val fields = psi.tupleFields
                if (fields != null) {
                    appendCommaList(fields.tupleFieldDeclList.map { it.typeReference.text })
                }
            }
        }
    }
    var icon = psi.getIcon(0)
    if ((psi as? RsVisibilityOwner)?.isPublic == true) {
        icon = icon.addVisibilityIcon(true)
    }
    return PresentationData(presentation, null, icon, null)
}

private fun buildTemplateImplTypeName(psi: RsImplItem): String? {

    val populatePolyboundsMap = fun(type: String, typeBounds: List<RsPolybound>?, map: LinkedHashMap<String, MutableList<String>>): Unit {
        val boundsList = mutableListOf<String>()
        if (typeBounds != null) {
            typeBounds.mapNotNullTo(boundsList) { it.bound.traitRef?.path?.referenceName }
        }
        if (map.containsKey(type))
            map[type]!!.addAll(boundsList)
        else
            map.put(type, boundsList)
    }

    val boundsMap = LinkedHashMap<String, MutableList<String>>()
    val baseName = psi.typeReference?.baseType?.name ?: return null
    for (typeParameter in psi.typeParameters) {
        val name = typeParameter.name ?: continue
        populatePolyboundsMap(name, typeParameter.typeParamBounds?.childrenOfType<RsPolybound>(), boundsMap)
    }

    val wherePredList = psi.whereClause?.wherePredList
    if (wherePredList != null) {
        for (whereParam in wherePredList) {
            val name = whereParam.typeReference?.baseType?.name ?: continue
            populatePolyboundsMap(name, whereParam.typeParamBounds?.childrenOfType<RsPolybound>(), boundsMap)
        }
    }

    val paramsList = mutableListOf<String>()
    for ((key, value) in boundsMap) {
        val boundsString = value.joinToString(separator = " + ")
        when (boundsString.isEmpty()) {
            true -> paramsList.add(key)
            false -> paramsList.add("$key: $boundsString")
        }
    }
    if (paramsList.isEmpty()) return null
    val paramsString = paramsList.joinToString(prefix = "<", postfix = ">", separator = ", ")
    return "$baseName$paramsString"
}

private fun presentableName(psi: RsElement): String? = when (psi) {
    is RsNamedElement -> psi.name
    is RsImplItem -> {
        val typeName = psi.typeReference?.type?.toString()
        val traitName = psi.traitRef?.path?.referenceName
        val templateImplName = buildTemplateImplTypeName(psi)
        when {
            typeName == null -> null
            templateImplName != null -> templateImplName
            traitName == null -> typeName
            else -> "$traitName for $typeName"
        }
    }
    else -> null
}

val RsDocAndAttributeOwner.presentableQualifiedName: String?
    get() {
        val qName = (this as? RsQualifiedNamedElement)?.qualifiedName
        if (qName != null) return qName<commit_msg>simplified code, removed doplicated logic<commit_after>/*
 * Use of this source code is governed by the MIT license that can be
 * found in the LICENSE file.
 */

package org.rust.ide.presentation

import com.intellij.ide.projectView.PresentationData
import com.intellij.navigation.ItemPresentation
import com.intellij.openapi.util.text.StringUtil
import org.rust.ide.icons.addVisibilityIcon
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.*
import org.rust.lang.core.types.type


fun getPresentation(psi: RsElement): ItemPresentation {
    val location = run {
        val mod = psi.containingMod
        "(in ${mod.qualifiedName ?: mod.modName ?: psi.containingFile.name})"
    }

    val name = presentableName(psi)
    return PresentationData(name, location, psi.getIcon(0), null)
}

fun getPresentationForStructure(psi: RsElement): ItemPresentation {
    val presentation = buildString {
        fun appendCommaList(xs: List<String>) {
            append('(')
            append(xs.joinToString(", "))
            append(')')
        }
        append(presentableName(psi))
        when (psi) {
            is RsFunction -> {
                appendCommaList(psi.valueParameters.mapNotNull { it.typeReference?.text })

                val ret = psi.retType?.typeReference
                if (ret != null) append(" -> ${ret.text}")
            }
            is RsConstant -> {
                psi.typeReference?.let { append(": ${it.text}") }
            }
            is RsFieldDecl -> {
                psi.typeReference?.let { append(": ${it.text}") }
            }
            is RsEnumVariant -> {
                val fields = psi.tupleFields
                if (fields != null) {
                    appendCommaList(fields.tupleFieldDeclList.map { it.typeReference.text })
                }
            }
        }
    }
    var icon = psi.getIcon(0)
    if ((psi as? RsVisibilityOwner)?.isPublic == true) {
        icon = icon.addVisibilityIcon(true)
    }
    return PresentationData(presentation, null, icon, null)
}

private fun buildTemplateImplTypeName(psi: RsImplItem): String? {
    val boundsMap = LinkedHashMap<String, MutableList<String>>()
    val baseName = psi.typeReference?.baseType?.name ?: return null
    for (typeParameter in psi.typeParameters) {
        val name = typeParameter.name ?: continue
        val boundsList = mutableListOf<String>()
        typeParameter.bounds.mapNotNullTo(boundsList) { it.bound.traitRef?.path?.referenceName }
        if (boundsMap.containsKey(name))
            boundsMap[name]!!.addAll(boundsList)
        else
            boundsMap.put(name, boundsList)
    }

    val paramsList = mutableListOf<String>()
    for ((key, value) in boundsMap) {
        val boundsString = value.joinToString(separator = " + ")
        when (boundsString.isEmpty()) {
            true -> paramsList.add(key)
            false -> paramsList.add("$key: $boundsString")
        }
    }

    if (paramsList.isEmpty()) return null
    val paramsString = paramsList.joinToString(prefix = "<", postfix = ">", separator = ", ")
    return "$baseName$paramsString"
}

private fun presentableName(psi: RsElement): String? = when (psi) {
    is RsNamedElement -> psi.name
    is RsImplItem -> {
        val typeName = psi.typeReference?.type?.toString()
        val traitName = psi.traitRef?.path?.referenceName
        val templateImplName = buildTemplateImplTypeName(psi)
        when {
            typeName == null -> null
            templateImplName != null -> templateImplName
            traitName == null -> typeName
            else -> "$traitName for $typeName"
        }
    }
    else -> null
}

val RsDocAndAttributeOwner.presentableQualifiedName: String?
    get() {
        val qName = (this as? RsQualifiedNamedElement)?.qualifiedName
        if (qName != null) return qName
{'fraction_non_alphanumeric': 0.11550556361877116, 'fraction_numerical': 0.0004837929366231253, 'mean_word_length': 2.4425478767693587, 'pattern_counts': {'":': 4, '<': 20, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5319501', 'n_tokens_mistral': 2366, 'n_tokens_neox': 2330, 'n_words': 504}