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

org.jetbrains.kotlin.backend.common.phaser.DumperVerifier.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2021 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.phaser

import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import java.io.File

private val IrElement.elementName: String
    get() = when (this) {
        is IrModuleFragment ->
            this.name.asString()

        is IrFile ->
            this.name

        else ->
            this.toString()
    }

private fun ActionState.isDumpNeeded() =
    when (beforeOrAfter) {
        BeforeOrAfter.BEFORE -> config.shouldDumpStateBefore(phase)
        BeforeOrAfter.AFTER -> config.shouldDumpStateAfter(phase)
    }

private fun ActionState.isValidationNeeded() =
    when (beforeOrAfter) {
        BeforeOrAfter.BEFORE -> config.shouldValidateStateBefore(phase)
        BeforeOrAfter.AFTER -> config.shouldValidateStateAfter(phase)
    }

fun  makeDumpAction(dumper: Action): Action =
    { phaseState, data, context ->
        if (phaseState.isDumpNeeded())
            dumper(phaseState, data, context)
    }

fun  makeVerifyAction(verifier: (Context, Data) -> Unit): Action =
    { phaseState, data, context ->
        if (phaseState.isValidationNeeded())
            verifier(context, data)
    }

fun dumpIrElement(actionState: ActionState, data: IrElement, @Suppress("UNUSED_PARAMETER") context: Any?): String {
    val beforeOrAfterStr = actionState.beforeOrAfter.name.toLowerCaseAsciiOnly()

    var dumpText = ""
    val elementName: String

    val dumpStrategy = System.getProperty("org.jetbrains.kotlin.compiler.ir.dump.strategy")
    val dump: IrElement.() -> String = if (dumpStrategy == "KotlinLike") IrElement::dumpKotlinLike else IrElement::dump

    val dumpOnlyFqName = actionState.config.dumpOnlyFqName
    if (dumpOnlyFqName != null) {
        elementName = dumpOnlyFqName
        data.acceptVoid(object : IrElementVisitorVoid {
            override fun visitElement(element: IrElement) {
                element.acceptChildrenVoid(this)
            }

            override fun visitDeclaration(declaration: IrDeclarationBase) {
                if (declaration is IrDeclarationWithName && FqName(dumpOnlyFqName) == declaration.fqNameWhenAvailable) {
                    dumpText += declaration.dump()
                } else {
                    super.visitDeclaration(declaration)
                }
            }
        })
    } else {
        elementName = data.elementName
        dumpText = data.dump()
    }

    val title = "// --- IR for $elementName $beforeOrAfterStr ${actionState.phase.description}\n"
    return title + dumpText
}

typealias Dumper = (ActionState, Data, Context) -> String?

fun  dumpToFile(
    fileExtension: String,
    dumper: Dumper
): Action =
    fun(actionState: ActionState, data: Data, context: Context) {
        val directoryPath = actionState.config.dumpToDirectory ?: return
        val dumpContent = dumper(actionState, data, context) ?: return

        // TODO in JVM BE most of lowerings run per file and "dump" is called per file,
        //  so each run of this function overwrites dump written for the previous one.
        val directoryFile =
            File(directoryPath +
                         ((data as? IrModuleFragment)?.let { "/" + it.name.asString().removeSurrounding("<", ">") } ?: ""))
        if (!directoryFile.isDirectory)
            if (!directoryFile.mkdirs())
                error("Can't create directory for IR dumps at $directoryPath")

        // Make dump files in a directory sorted by ID
        val phaseIdFormatted = "%02d".format(actionState.phaseCount)

        val dumpStrategy = System.getProperty("org.jetbrains.kotlin.compiler.ir.dump.strategy")
        val extPrefix = if (dumpStrategy == "KotlinLike") "kt." else ""

        val fileName = "${phaseIdFormatted}_${actionState.beforeOrAfter}.${actionState.phase.name}.$extPrefix$fileExtension"

        File(directoryFile, fileName).writeText(dumpContent)
    }

fun  dumpToStdout(
    dumper: Dumper
): Action =
    fun(actionState: ActionState, data: Data, context: Context) {
        if (actionState.config.dumpToDirectory != null) return
        val dumpContent = dumper(actionState, data, context) ?: return
        println("\n\n----------------------------------------------")
        println(dumpContent)
        println()
    }

val defaultDumper = makeDumpAction(dumpToStdout(::dumpIrElement) + dumpToFile("ir", ::dumpIrElement))

fun validationCallback(context: CommonBackendContext, fragment: IrElement, checkProperties: Boolean = false) {
    val validatorConfig = IrValidatorConfig(
        abortOnError = true,
        ensureAllNodesAreDifferent = true,
        checkTypes = false,
        checkDescriptors = false,
        checkProperties = checkProperties,
    )
    fragment.accept(IrValidator(context, validatorConfig), null)
    fragment.checkDeclarationParents()
}

val validationAction = makeVerifyAction(::validationCallback)

class IrValidationPhase(private val context: CommonBackendContext) : ModuleLoweringPass {
    override fun lower(irModule: IrModuleFragment) {
        validationCallback(context, irModule)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy