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

tagan.validation-impl.1.5.1.source-code.validation.kt Maven / Gradle / Ivy

Go to download

Yatagan is a Dependency Injection framework, specializing on runtime performance and build speed. Supports code generation (apt/kapt/ksp) or reflection.

The newest version!
/*
 * Copyright 2022 Yandex LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yandex.yatagan.validation.impl

import com.yandex.yatagan.base.traverseDepthFirstWithPath
import com.yandex.yatagan.base.zipWithNextOrNull
import com.yandex.yatagan.core.model.ClassBackedModel
import com.yandex.yatagan.lang.Type
import com.yandex.yatagan.validation.LocatedMessage
import com.yandex.yatagan.validation.MayBeInvalid
import com.yandex.yatagan.validation.ValidationMessage
import com.yandex.yatagan.validation.Validator
import com.yandex.yatagan.validation.format.Strings
import com.yandex.yatagan.validation.format.reportError
import kotlin.LazyThreadSafetyMode.NONE

private class ValidatorImpl : Validator {
    private val _children = arrayListOf()
    val children: List
        get() = _children
    private val _messages = lazy(NONE) { arrayListOf() }
    val messages: List
        get() = if (_messages.isInitialized()) _messages.value else emptyList()

    override fun report(message: ValidationMessage) {
        _messages.value += message
    }

    override fun child(node: MayBeInvalid) {
        _children += node
    }

    override fun inline(node: MayBeInvalid) {
        if (node is ClassBackedModel) {
            val type = node.type
            // A uniform mechanism of reporting unresolved types.
            if (type.isInvalid()) {
                reportError(Strings.Errors.invalidType(type)) {
                    if ("unresolved-type-var" in type.toString()) {
                        addNote(Strings.Notes.unresolvedTypeVar())
                    } else {
                        addNote(Strings.Notes.whyTypeCanBeUnresolved())
                    }
                }
            }
        }
        node.validate(this)
    }
}

fun validate(
    root: MayBeInvalid,
): Collection {
    val cache = hashMapOf()
    val result: MutableMap>> = mutableMapOf()

    traverseDepthFirstWithPath(
        roots = listOf(root),
        childrenOf = { cache[it]?.children ?: emptyList() },
        visit = { path, node ->
            val validator = cache.getOrPut(node) {
                ValidatorImpl().also { validator -> validator.inline(node) }
            }
            for (message in validator.messages) {
                // Extract current path from stack::substack
                result.getOrPut(message, ::mutableSetOf) += path.toList()
            }
        }
    )

    return result.map { (message, paths) ->
        val pathStrings: MutableList> = paths.mapTo(arrayListOf()) { path: List ->
            path.zipWithNextOrNull { node: MayBeInvalid, itsChild: MayBeInvalid? ->
                node.toString(childContext = itsChild)
            }
        }
        pathStrings.sortWith(PathComparator)

        LocatedMessage(
            message = object : ValidationMessage by message {
                override val notes: Collection = message.notes.sortedWith(CharSequenceComparator)
            },
            encounterPaths = pathStrings,
        )
    }
}

private fun Type.isInvalid(): Boolean {
    return isUnresolved || typeArguments.any(Type::isInvalid)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy