AA: introduce static project structure provider by compiler configuration

Also add standalone mode utils to configure Application/Project environments
This commit is contained in:
Jinseong Jeon
2022-02-02 00:02:36 -08:00
committed by Ilya Kirillov
parent d219de0f88
commit 26e923e3ae
30 changed files with 713 additions and 88 deletions
@@ -3,18 +3,18 @@
* 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.analysis.api.impl.base.test.utils.libraries
package org.jetbrains.kotlin.analysis.api.impl.base.util
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.util.io.URLUtil.JAR_SEPARATOR
import java.nio.file.Path
import kotlin.io.path.absolutePathString
object TestLibraryUtils {
object LibraryUtils {
fun getAllVirtualFilesFromJar(jar: Path): Collection<VirtualFile> {
val jarFileSystem = CoreJarFileSystem()
val root = jarFileSystem.refreshAndFindFileByPath(jar.absolutePathString() + "!/")!!
val root = jarFileSystem.refreshAndFindFileByPath(jar.toAbsolutePath().toString() + JAR_SEPARATOR)!!
val files = mutableSetOf<VirtualFile>()
VfsUtilCore.iterateChildrenRecursively(
@@ -29,4 +29,4 @@ object TestLibraryUtils {
)
return files
}
}
}
@@ -5,19 +5,15 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.components.RendererModifier
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.impl.base.test.TestReferenceResolveResultRenderer.renderResolvedTo
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
@@ -52,7 +48,7 @@ abstract class AbstractReferenceResolveTest : AbstractHLApiSingleModuleTest() {
) {
val symbols = ktReferences.flatMap { it.resolveToSymbols() }
checkReferenceResultForValidity(ktReferences, module, testServices, symbols)
renderResolvedTo(symbols)
renderResolvedTo(symbols, renderingOptions)
}
if (Directives.UNRESOLVED_REFERENCE in module.directives) {
@@ -83,49 +79,6 @@ abstract class AbstractReferenceResolveTest : AbstractHLApiSingleModuleTest() {
}
}
private fun KtAnalysisSession.renderResolvedTo(symbols: List<KtSymbol>) =
symbols.map { renderResolveResult(it) }
.sorted()
.withIndex()
.joinToString(separator = "\n") { "${it.index}: ${it.value}" }
private fun KtAnalysisSession.renderResolveResult(symbol: KtSymbol): String {
return buildString {
symbolContainerFqName(symbol)?.let { fqName ->
append("(in $fqName) ")
}
when (symbol) {
is KtDeclarationSymbol -> append(symbol.render(renderingOptions))
is KtPackageSymbol -> append("package ${symbol.fqName}")
is KtReceiverParameterSymbol -> {
append("extension receiver with type ")
append(symbol.type.render(renderingOptions.typeRendererOptions))
}
else -> error("Unexpected symbol ${symbol::class}")
}
}
}
@Suppress("unused")// KtAnalysisSession receiver
private fun KtAnalysisSession.symbolContainerFqName(symbol: KtSymbol): String? {
if (symbol is KtPackageSymbol || symbol is KtValueParameterSymbol) return null
val nonLocalFqName = when (symbol) {
is KtConstructorSymbol -> symbol.containingClassIdIfNonLocal?.asSingleFqName()
is KtCallableSymbol -> symbol.callableIdIfNonLocal?.asSingleFqName()?.parent()
is KtClassLikeSymbol -> symbol.classIdIfNonLocal?.asSingleFqName()?.parent()
else -> null
}
when (nonLocalFqName) {
null -> Unit
FqName.ROOT -> return "ROOT"
else -> return nonLocalFqName.asString()
}
val container = (symbol as? KtSymbolWithKind)?.getContainingSymbol() ?: return null
val parents = generateSequence(container) { it.getContainingSymbol() }.toList().asReversed()
return "<local>: " + parents.joinToString(separator = ".") { (it as? KtNamedSymbol)?.name?.asString() ?: "<no name>" }
}
private object Directives : SimpleDirectivesContainer() {
val UNRESOLVED_REFERENCE by directive(
"Reference should be unresolved",
@@ -137,9 +90,4 @@ abstract class AbstractReferenceResolveTest : AbstractHLApiSingleModuleTest() {
sortNestedDeclarations = true
)
private fun PsiReference.unwrapMultiReferences(): List<PsiReference> = when (this) {
is KtReference -> listOf(this)
is PsiMultiReference -> references.flatMap { it.unwrapMultiReferences() }
else -> error("Unexpected reference $this")
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2022 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.analysis.api.impl.base.test
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
import org.jetbrains.kotlin.name.FqName
object TestReferenceResolveResultRenderer {
fun KtAnalysisSession.renderResolvedTo(
symbols: List<KtSymbol>,
renderingOptions: KtDeclarationRendererOptions = KtDeclarationRendererOptions.DEFAULT
) =
symbols.map { renderResolveResult(it, renderingOptions) }
.sorted()
.withIndex()
.joinToString(separator = "\n") { "${it.index}: ${it.value}" }
private fun KtAnalysisSession.renderResolveResult(
symbol: KtSymbol,
renderingOptions: KtDeclarationRendererOptions
): String {
return buildString {
symbolContainerFqName(symbol)?.let { fqName ->
append("(in $fqName) ")
}
when (symbol) {
is KtDeclarationSymbol -> append(symbol.render(renderingOptions))
is KtPackageSymbol -> append("package ${symbol.fqName}")
is KtReceiverParameterSymbol -> {
append("extension receiver with type ")
append(symbol.type.render(renderingOptions.typeRendererOptions))
}
else -> error("Unexpected symbol ${symbol::class}")
}
}
}
@Suppress("unused")// KtAnalysisSession receiver
private fun KtAnalysisSession.symbolContainerFqName(symbol: KtSymbol): String? {
if (symbol is KtPackageSymbol || symbol is KtValueParameterSymbol) return null
val nonLocalFqName = when (symbol) {
is KtConstructorSymbol -> symbol.containingClassIdIfNonLocal?.asSingleFqName()
is KtCallableSymbol -> symbol.callableIdIfNonLocal?.asSingleFqName()?.parent()
is KtClassLikeSymbol -> symbol.classIdIfNonLocal?.asSingleFqName()?.parent()
else -> null
}
when (nonLocalFqName) {
null -> Unit
FqName.ROOT -> return "ROOT"
else -> return nonLocalFqName.asString()
}
val container = (symbol as? KtSymbolWithKind)?.getContainingSymbol() ?: return null
val parents = generateSequence(container) { it.getContainingSymbol() }.toList().asReversed()
return "<local>: " + parents.joinToString(separator = ".") { (it as? KtNamedSymbol)?.name?.asString() ?: "<no name>" }
}
}
@@ -8,14 +8,14 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils.offsetToLineAndColumn
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.psi.*
inline fun <T> runReadAction(crossinline runnable: () -> T): T {
return ApplicationManager.getApplication().runReadAction(Computable { runnable() })
@@ -51,3 +51,12 @@ fun String.indented(indent: Int): String {
fun KtDeclaration.getNameWithPositionString(): String {
return (presentation?.presentableText ?: name ?: this::class.simpleName) + "@" + position()
}
fun findReferencesAtCaret(mainKtFile: KtFile, caretPosition: Int): List<KtReference> =
mainKtFile.findReferenceAt(caretPosition)?.unwrapMultiReferences().orEmpty().filterIsInstance<KtReference>()
fun PsiReference.unwrapMultiReferences(): List<PsiReference> = when (this) {
is KtReference -> listOf(this)
is PsiMultiReference -> references.flatMap { it.unwrapMultiReferences() }
else -> error("Unexpected reference $this")
}