All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.fir.analysis.checkers

import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name

/**
 * Provides representations for FirElement's.
 */
interface FirDeclarationPresenter {
    fun StringBuilder.appendRepresentation(it: FirElement) {
        append("NO_REPRESENTATION")
    }

    fun StringBuilder.appendRepresentation(it: ClassId) {
        append(it.packageFqName.asString())
        append('/')
        append(it.relativeClassName.asString())
    }

    fun StringBuilder.appendRepresentation(it: CallableId) {
        if (it.className != null) {
            append(it.packageName.asString())
            append('/')
            append(it.className)
            append('.')
            append(it.callableName)
        } else {
            append(it.packageName.asString())
            append('/')
            append(it.callableName)
        }
    }

    fun StringBuilder.appendRepresentation(it: ConeTypeProjection) {
        when (it) {
            ConeStarProjection -> {
                append('*')
            }
            is ConeKotlinTypeProjectionIn -> {
                append("in ")
                appendRepresentation(it.type)
            }
            is ConeKotlinTypeProjectionOut -> {
                append("out ")
                appendRepresentation(it.type)
            }
            is ConeKotlinType -> {
                appendRepresentation(it)
            }
        }
    }

    fun StringBuilder.appendRepresentation(it: ConeKotlinType) {
        when (it) {
            is ConeDefinitelyNotNullType -> {
                appendRepresentation(it.original)
                append(it.nullability.suffix)
            }
            is ConeClassErrorType -> {
                append("ERROR(")
                append(it.diagnostic.reason)
                append(')')
            }
            is ConeCapturedType -> {
                append(it.constructor.projection)
                append(it.nullability.suffix)
            }
            is ConeClassLikeType -> {
                appendRepresentation(it.lookupTag.classId)
                if (it.typeArguments.isNotEmpty()) {
                    append('<')
                    it.typeArguments.forEach { that ->
                        appendRepresentation(that)
                        append(',')
                    }
                    append('>')
                }
                append(it.nullability.suffix)
            }
            is ConeLookupTagBasedType -> {
                append(it.lookupTag.name)
                append(it.nullability.suffix)
            }
            is ConeIntegerLiteralType -> {
                append(it.value)
                append(it.nullability.suffix)
            }
            is ConeFlexibleType,
            is ConeIntersectionType,
            is ConeStubType -> {
                append("ERROR")
            }
        }
    }

    fun StringBuilder.appendRepresentation(it: FirTypeRef) {
        when (it) {
            is FirResolvedTypeRef -> appendRepresentation(it.type)
            is FirErrorTypeRef -> append("ERROR")
            else -> append("?")
        }
    }

    fun StringBuilder.appendRepresentation(it: FirTypeParameter) {
        append(it.name.asString())
        append(':')
        when (it.bounds.size) {
            0 -> {
            }
            1 -> {
                appendRepresentation(it.bounds[0])
            }
            else -> {
                val set = sortedSetOf()
                it.bounds.forEach { that ->
                    set.add(buildString { appendRepresentation(that) })
                }
                set.forEach { that ->
                    append(that)
                    append(',')
                }
            }
        }
    }

    fun StringBuilder.appendRepresentation(it: FirValueParameter) {
        if (it.isVararg) {
            append("vararg ")
        }
        appendRepresentation(it.returnTypeRef)
    }

    fun represent(it: FirProperty) = buildString {
        append('[')
        it.receiverTypeRef?.let {
            appendRepresentation(it)
        }
        append(']')
        appendRepresentation(it.symbol.callableId)
    }

    fun represent(it: FirSimpleFunction) = buildString {
        append('<')
        it.typeParameters.forEach {
            appendRepresentation(it)
            append(',')
        }
        append('>')
        append('[')
        it.receiverTypeRef?.let {
            appendRepresentation(it)
        }
        append(']')
        if (it.isOperator) {
            append("operator ")
        }
        appendRepresentation(it.symbol.callableId)
        append('(')
        it.valueParameters.forEach {
            appendRepresentation(it)
            append(',')
        }
        append(')')
    }

    fun represent(it: FirTypeAlias) = buildString {
        append('[')
        append(']')
        appendRepresentation(it.symbol.classId)
    }

    fun represent(it: FirRegularClass) = buildString {
        append('[')
        append(']')
        appendRepresentation(it.symbol.classId)
    }
}

private class FirDefaultDeclarationPresenter : FirDeclarationPresenter

private val NO_NAME_PROVIDED = Name.special("")

// - see testEnumValuesValueOf.
// it generates a static function that has
// the same signature as the function defined
// explicitly.
// - see tests with `fun () {}`.
// you can't redeclare something that has no name.
private fun FirDeclaration.isCollectable() = when (this) {
    is FirSimpleFunction -> source?.kind !is FirFakeSourceElementKind && name != NO_NAME_PROVIDED
    is FirRegularClass -> name != NO_NAME_PROVIDED
    else -> true
}

/**
 * Collects FirDeclarations for further analysis.
 */
class FirDeclarationInspector(
    private val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
) {
    val otherDeclarations = mutableMapOf>()
    val functionDeclarations = mutableMapOf>()

    fun collect(declaration: FirDeclaration) {
        if (!declaration.isCollectable()) {
            return
        }

        if (declaration is FirSimpleFunction) {
            return collectFunction(declaration)
        }

        val key = when (declaration) {
            is FirRegularClass -> presenter.represent(declaration)
            is FirTypeAlias -> presenter.represent(declaration)
            is FirProperty -> presenter.represent(declaration)
            else -> return
        }

        var value = otherDeclarations[key]

        if (value == null) {
            value = mutableListOf()
            otherDeclarations[key] = value
        }

        value.add(declaration)
    }

    private fun collectFunction(declaration: FirSimpleFunction) {
        val key = presenter.represent(declaration)
        var value = functionDeclarations[key]

        if (value == null) {
            value = mutableListOf()
            functionDeclarations[key] = value
        }

        value.add(declaration)
    }

    fun contains(declaration: FirDeclaration) = when (declaration) {
        is FirSimpleFunction -> presenter.represent(declaration) in functionDeclarations
        is FirRegularClass -> presenter.represent(declaration) in otherDeclarations
        is FirTypeAlias -> presenter.represent(declaration) in otherDeclarations
        is FirProperty -> presenter.represent(declaration) in otherDeclarations
        else -> false
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy