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

org.jetbrains.kotlin.fir.lightTree.LightTree2Fir.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2019 JetBrains s.r.o. 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.lightTree

import com.intellij.lang.LighterASTNode
import com.intellij.lang.PsiBuilderFactory
import com.intellij.lang.impl.PsiBuilderImpl
import com.intellij.openapi.util.Ref
import com.intellij.psi.TokenType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtIoFileSourceFile
import org.jetbrains.kotlin.KtSourceFile
import org.jetbrains.kotlin.KtSourceFileLinesMapping
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.lightTree.converter.LightTreeRawFirDeclarationBuilder
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.lexer.KotlinLexer
import org.jetbrains.kotlin.parsing.KotlinLightParser
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.readSourceFileWithMapping
import java.io.File
import java.nio.file.Path

class LightTree2Fir(
    val session: FirSession,
    private val scopeProvider: FirScopeProvider,
    private val diagnosticsReporter: DiagnosticReporter? = null,
) {
    companion object {
        private val parserDefinition = KotlinParserDefinition()
        private fun makeLexer() = KotlinLexer()

        fun buildLightTree(
            code: CharSequence,
            errorListener: LightTreeParsingErrorListener?,
        ): FlyweightCapableTreeStructure {
            val builder = PsiBuilderFactory.getInstance().createBuilder(parserDefinition, makeLexer(), code)
            return KotlinLightParser.parse(builder).also {
                if (errorListener != null) reportErrors(it.root, it, errorListener)
            }
        }

        private fun reportErrors(
            node: LighterASTNode,
            tree: FlyweightCapableTreeStructure,
            errorListener: LightTreeParsingErrorListener,
            ref: Ref> = Ref>(),
        ) {
            tree.getChildren(node, ref)
            val kidsArray = ref.get() ?: return

            for (kid in kidsArray) {
                if (kid == null) break
                val tokenType = kid.tokenType
                if (tokenType == TokenType.ERROR_ELEMENT) {
                    val message = PsiBuilderImpl.getErrorMessage(kid)
                    errorListener.onError(kid.startOffset, kid.endOffset, message)
                }

                ref.set(null)
                reportErrors(kid, tree, errorListener, ref)
            }
        }

    }

    fun buildFirFile(path: Path): FirFile {
        return buildFirFile(path.toFile())
    }

    fun buildFirFile(file: File): FirFile {
        val sourceFile = KtIoFileSourceFile(file)
        val (code, linesMapping) = with(file.inputStream().reader(Charsets.UTF_8)) {
            this.readSourceFileWithMapping()
        }
        return buildFirFile(code, sourceFile, linesMapping)
    }

    fun buildFirFile(
        lightTree: FlyweightCapableTreeStructure,
        sourceFile: KtSourceFile,
        linesMapping: KtSourceFileLinesMapping,
    ): FirFile {
        return LightTreeRawFirDeclarationBuilder(session, scopeProvider, lightTree)
            .convertFile(lightTree.root, sourceFile, linesMapping)
    }

    fun buildFirFile(code: CharSequence, sourceFile: KtSourceFile, linesMapping: KtSourceFileLinesMapping): FirFile {
        val errorListener = makeErrorListener(sourceFile)
        val lightTree = buildLightTree(code, errorListener)
        return buildFirFile(lightTree, sourceFile, linesMapping)
    }

    private fun makeErrorListener(sourceFile: KtSourceFile): LightTreeParsingErrorListener? {
        val diagnosticsReporter = diagnosticsReporter ?: return null
        return diagnosticsReporter.toKotlinParsingErrorListener(sourceFile, session.languageVersionSettings)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy