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

org.jetbrains.kotlin.backend.common.checkers.IrInlineDeclarationChecker.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2010-2024 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.backend.common.checkers

import org.jetbrains.kotlin.backend.common.checkers.IrInlineDeclarationChecker.InlineFunctionInfo
import org.jetbrains.kotlin.backend.common.diagnostics.SerializationErrors
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.overrides.isEffectivelyPrivate
import org.jetbrains.kotlin.ir.overrides.isNonPrivate
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.parents
import org.jetbrains.kotlin.ir.visitors.IrTypeVisitor

/**
 * Reports an IR-level diagnostic whenever a private type is used within an `inline` function with broader visibility.
 */
class IrInlineDeclarationChecker(
    private val diagnosticReporter: IrDiagnosticReporter,
) : IrTypeVisitor() {

    data class InlineFunctionInfo(
        val file: IrFile,
        val insideEffectivelyPrivateDeclaration: Boolean = false,
        val inlineFunction: IrFunction? = null,
    ) {
        fun insideDeclaration(declaration: IrDeclaration, inlineFunction: IrFunction? = this.inlineFunction): InlineFunctionInfo {
            if (this.inlineFunction != null) return this
            if (declaration !is IrDeclarationWithVisibility) return this
            return InlineFunctionInfo(
                file,
                insideEffectivelyPrivateDeclaration || !declaration.isNonPrivate,
                inlineFunction,
            )
        }
    }

    override fun visitType(container: IrElement, type: IrType, data: InlineFunctionInfo?) {
        val inlineFunction = data?.inlineFunction ?: return
        val klass = type.classifierOrNull?.takeIf { it.isBound }?.owner as? IrClass ?: return
        if (!data.insideEffectivelyPrivateDeclaration &&
            klass.isEffectivelyPrivate() &&
            klass.parents.none { it == inlineFunction } // local/private classed declared in the current inline function are legal.
        ) {
            diagnosticReporter.at(container, data.file).report(
                SerializationErrors.IR_PRIVATE_TYPE_USED_IN_NON_PRIVATE_INLINE_FUNCTION,
                inlineFunction,
                klass,
            )
        }
    }

    override fun visitElement(element: IrElement, data: InlineFunctionInfo?) {
        element.acceptChildren(this, data)
    }

    override fun visitFile(declaration: IrFile, data: InlineFunctionInfo?) {
        declaration.acceptChildren(this, InlineFunctionInfo(declaration))
    }

    override fun visitClass(declaration: IrClass, data: InlineFunctionInfo?) {
        declaration.acceptChildren(this, data?.insideDeclaration(declaration))
    }

    override fun visitFunction(declaration: IrFunction, data: InlineFunctionInfo?) {
        declaration.acceptChildren(this, data?.insideDeclaration(declaration, declaration.takeIf { it.isInline }))
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy