Add FIR enhancement tests, fix some exceptions / problems around them
Test data and tests themselves are based on compiler/testData/loadJava/compiledJava
This commit is contained in:
@@ -207,7 +207,7 @@ private fun JavaAnnotationArgument.toFirExpression(session: FirSession): FirExpr
|
||||
null
|
||||
}
|
||||
this.calleeReference = calleeReference
|
||||
?: FirErrorNamedReference(session, null, "Strange Java enum value: ${this@toFirExpression}")
|
||||
?: FirErrorNamedReference(session, null, "Strange Java enum value: $classId.$entryName")
|
||||
}
|
||||
}
|
||||
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
|
||||
|
||||
+6
-3
@@ -53,9 +53,12 @@ internal class EnhancementSignatureParts(
|
||||
}
|
||||
|
||||
val containsFunctionN = current.toNotNullConeKotlinType().contains {
|
||||
val classId = it.lookupTag.classId
|
||||
classId.shortClassName == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME.shortName() &&
|
||||
classId.asSingleFqName() == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME
|
||||
if (it is ConeClassErrorType) false
|
||||
else {
|
||||
val classId = it.lookupTag.classId
|
||||
classId.shortClassName == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME.shortName() &&
|
||||
classId.asSingleFqName() == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME
|
||||
}
|
||||
}
|
||||
|
||||
val enhancedCurrent = current.enhance(qualifiersWithPredefined ?: qualifiers)
|
||||
|
||||
+1
-6
@@ -10,8 +10,6 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
@@ -50,10 +48,7 @@ class FirAnnotationTypeQualifierResolver(private val jsr305State: Jsr305State) {
|
||||
}
|
||||
|
||||
private val FirAnnotationCall.resolvedClass: FirRegularClass?
|
||||
get() {
|
||||
val lookupTag = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag
|
||||
return (lookupTag?.toSymbol(session) as? FirClassSymbol)?.fir
|
||||
}
|
||||
get() = (coneClassLikeType?.lookupTag?.toSymbol(session) as? FirClassSymbol)?.fir
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotationCall: FirAnnotationCall): FirAnnotationCall? {
|
||||
if (jsr305State.disabled) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
FIR enhancement tests use compiler/testData/loadJava/compilerJava
|
||||
@@ -27,7 +27,7 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
|
||||
|
||||
val scope = GlobalSearchScope.filesScope(project, ktFiles.mapNotNull { it.virtualFile })
|
||||
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
|
||||
val session = createSession(scope)
|
||||
val session = createSession(project, scope)
|
||||
|
||||
val builder = RawFirBuilder(session, stubMode = false)
|
||||
|
||||
|
||||
-15
@@ -24,19 +24,4 @@ abstract class AbstractFirResolveWithSessionTestCase : KotlinTestWithEnvironment
|
||||
.unregisterExtension(JavaElementFinder::class.java)
|
||||
}
|
||||
|
||||
open fun createSession(sourceScope: GlobalSearchScope): FirSession {
|
||||
val moduleInfo = FirTestModuleInfo()
|
||||
val provider = FirProjectSessionProvider(project)
|
||||
return FirJavaModuleBasedSession(moduleInfo, provider, sourceScope).also {
|
||||
createSessionForDependencies(provider, moduleInfo, sourceScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSessionForDependencies(
|
||||
provider: FirProjectSessionProvider, moduleInfo: FirTestModuleInfo, sourceScope: GlobalSearchScope
|
||||
) {
|
||||
val dependenciesInfo = FirTestModuleInfo()
|
||||
moduleInfo.dependencies.add(dependenciesInfo)
|
||||
FirLibrarySession(dependenciesInfo, provider, GlobalSearchScope.notScope(sourceScope))
|
||||
}
|
||||
}
|
||||
-15
@@ -16,19 +16,4 @@ import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
||||
|
||||
abstract class AbstractFirResolveWithSessionTestCase : KotlinTestWithEnvironment() {
|
||||
|
||||
open fun createSession(sourceScope: GlobalSearchScope): FirSession {
|
||||
val moduleInfo = FirTestModuleInfo()
|
||||
val provider = FirProjectSessionProvider(project)
|
||||
return FirJavaModuleBasedSession(moduleInfo, provider, sourceScope).also {
|
||||
createSessionForDependencies(provider, moduleInfo, sourceScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSessionForDependencies(
|
||||
provider: FirProjectSessionProvider, moduleInfo: FirTestModuleInfo, sourceScope: GlobalSearchScope
|
||||
) {
|
||||
val dependenciesInfo = FirTestModuleInfo()
|
||||
moduleInfo.dependencies.add(dependenciesInfo)
|
||||
FirLibrarySession(dependenciesInfo, provider, GlobalSearchScope.notScope(sourceScope))
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class FirResolveTestTotalKotlin : AbstractFirResolveWithSessionTestCase() {
|
||||
}
|
||||
|
||||
val scope = ProjectScope.getContentScope(project)
|
||||
val session = createSession(scope)
|
||||
val session = createSession(project, scope)
|
||||
val builder = RawFirBuilder(session, stubMode = true)
|
||||
|
||||
val totalTransformer = FirTotalResolveTransformer()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
|
||||
import org.jetbrains.kotlin.fir.java.FirLibrarySession
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
|
||||
fun createSession(project: Project, sourceScope: GlobalSearchScope): FirSession {
|
||||
val moduleInfo = FirTestModuleInfo()
|
||||
val provider = FirProjectSessionProvider(project)
|
||||
return FirJavaModuleBasedSession(moduleInfo, provider, sourceScope).also {
|
||||
createSessionForDependencies(provider, moduleInfo, sourceScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSessionForDependencies(
|
||||
provider: FirProjectSessionProvider, moduleInfo: FirTestModuleInfo, sourceScope: GlobalSearchScope
|
||||
) {
|
||||
val dependenciesInfo = FirTestModuleInfo()
|
||||
moduleInfo.dependencies.add(dependenciesInfo)
|
||||
FirLibrarySession(dependenciesInfo, provider, GlobalSearchScope.notScope(sourceScope))
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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.java
|
||||
|
||||
import com.intellij.lang.java.JavaLanguage
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.fir.FirRenderer
|
||||
import org.jetbrains.kotlin.fir.createSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.kotlin.test.*
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils.getAnnotationsJar
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils.newConfiguration
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
abstract class AbstractFirTypeEnhancementTest : KtUsefulTestCase() {
|
||||
private lateinit var javaFilesDir: File
|
||||
|
||||
private lateinit var environment: KotlinCoreEnvironment
|
||||
|
||||
val project: Project
|
||||
get() {
|
||||
return environment.project
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
javaFilesDir = KotlinTestUtils.tmpDirForTest(this)
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
FileUtil.delete(javaFilesDir)
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
private fun createJarWithForeignAnnotations(): File =
|
||||
MockLibraryUtil.compileJavaFilesLibraryToJar(FOREIGN_ANNOTATIONS_SOURCES_PATH, "foreign-annotations")
|
||||
|
||||
private fun createEnvironment(content: String): KotlinCoreEnvironment {
|
||||
val classpath = mutableListOf(getAnnotationsJar(), ForTestCompileRuntime.runtimeJarForTests())
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(content, "ANDROID_ANNOTATIONS")) {
|
||||
classpath.add(ForTestCompileRuntime.androidAnnotationsForTests())
|
||||
}
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(content, "JVM_ANNOTATIONS")) {
|
||||
classpath.add(ForTestCompileRuntime.jvmAnnotationsForTests())
|
||||
}
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(content, "FOREIGN_ANNOTATIONS")) {
|
||||
classpath.add(createJarWithForeignAnnotations())
|
||||
}
|
||||
return KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
newConfiguration(
|
||||
ConfigurationKind.JDK_NO_RUNTIME, TestJdkKind.FULL_JDK, classpath, listOf(javaFilesDir)
|
||||
),
|
||||
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
).apply {
|
||||
Extensions.getArea(project)
|
||||
.getExtensionPoint(PsiElementFinder.EP_NAME)
|
||||
.unregisterExtension(JavaElementFinder::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun doTest(path: String) {
|
||||
val javaFile = File(path)
|
||||
val javaLines = javaFile.readLines()
|
||||
val content = javaLines.joinToString(separator = "\n")
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(content, "SKIP_IN_FIR_TEST")) return
|
||||
|
||||
val srcFiles = KotlinTestUtils.createTestFiles<Void, File>(
|
||||
javaFile.name, FileUtil.loadFile(javaFile, true),
|
||||
object : KotlinTestUtils.TestFileFactoryNoModules<File>() {
|
||||
override fun create(fileName: String, text: String, directives: Map<String, String>): File {
|
||||
var currentDir = javaFilesDir
|
||||
if ("/" !in fileName) {
|
||||
val packageFqName =
|
||||
text.split("\n").firstOrNull {
|
||||
it.startsWith("package")
|
||||
}?.substringAfter("package")?.trim()?.substringBefore(";")?.let { name ->
|
||||
FqName(name)
|
||||
} ?: FqName.ROOT
|
||||
for (segment in packageFqName.pathSegments()) {
|
||||
currentDir = File(currentDir, segment.asString()).apply { mkdir() }
|
||||
}
|
||||
}
|
||||
val targetFile = File(currentDir, fileName)
|
||||
try {
|
||||
FileUtil.writeToFile(targetFile, text)
|
||||
} catch (e: IOException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
|
||||
return targetFile
|
||||
}
|
||||
}, ""
|
||||
)
|
||||
environment = createEnvironment(content)
|
||||
val virtualFiles = srcFiles.map {
|
||||
object : LightVirtualFile(
|
||||
it.name, JavaLanguage.INSTANCE, StringUtilRt.convertLineSeparators(it.readText())
|
||||
) {
|
||||
override fun getPath(): String {
|
||||
//TODO: patch LightVirtualFile
|
||||
return "/${it.name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
val factory = PsiFileFactory.getInstance(project) as PsiFileFactoryImpl
|
||||
val psiFiles = virtualFiles.map { factory.trySetupPsiForFile(it, JavaLanguage.INSTANCE, true, false)!! }
|
||||
|
||||
val scope = GlobalSearchScope.filesScope(project, virtualFiles)
|
||||
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
|
||||
val session = createSession(project, scope)
|
||||
|
||||
val topPsiClasses = psiFiles.flatMap { it.getChildrenOfType<PsiClass>().toList() }
|
||||
|
||||
val javaFirDump = StringBuilder().also { builder ->
|
||||
val renderer = FirRenderer(builder)
|
||||
val symbolProvider = session.service<FirSymbolProvider>() as FirCompositeSymbolProvider
|
||||
val javaProvider = symbolProvider.providers.filterIsInstance<JavaSymbolProvider>().first()
|
||||
|
||||
fun processClassWithChildren(psiClass: PsiClass, parentFqName: FqName) {
|
||||
val psiFile = psiClass.containingFile
|
||||
val packageStatement = psiFile.children.filterIsInstance<PsiPackageStatement>().firstOrNull()
|
||||
val packageName = packageStatement?.packageName
|
||||
val fqName = parentFqName.child(Name.identifier(psiClass.name!!))
|
||||
val classId = ClassId(packageName?.let { FqName(it) } ?: FqName.ROOT, fqName, false)
|
||||
javaProvider.getClassLikeSymbolByFqName(classId)
|
||||
?: throw AssertionError(classId.asString())
|
||||
psiClass.innerClasses.forEach {
|
||||
processClassWithChildren(psiClass = it, parentFqName = fqName)
|
||||
}
|
||||
}
|
||||
for (psiClass in topPsiClasses) {
|
||||
processClassWithChildren(psiClass, FqName.ROOT)
|
||||
}
|
||||
|
||||
val processedJavaClasses = mutableSetOf<FirJavaClass>()
|
||||
for (javaClass in javaProvider.getJavaTopLevelClasses().sortedBy { it.name }) {
|
||||
if (javaClass !is FirJavaClass || javaClass in processedJavaClasses) continue
|
||||
val enhancementScope = session.service<FirScopeProvider>().getDeclaredMemberScope(javaClass, session).let {
|
||||
when (it) {
|
||||
is FirCompositeScope -> it.scopes.filterIsInstance<JavaClassEnhancementScope>().first()
|
||||
is JavaClassEnhancementScope -> it
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
if (enhancementScope == null) {
|
||||
javaClass.accept(renderer, null)
|
||||
} else {
|
||||
renderer.visitMemberDeclaration(javaClass)
|
||||
renderer.renderSupertypes(javaClass)
|
||||
renderer.renderInBraces {
|
||||
val renderedDeclarations = mutableListOf<FirDeclaration>()
|
||||
for (declaration in javaClass.declarations) {
|
||||
if (declaration in renderedDeclarations) continue
|
||||
when (declaration) {
|
||||
is FirJavaMethod -> enhancementScope.processFunctionsByName(declaration.name) { symbol ->
|
||||
val enhanced = (symbol as? FirFunctionSymbol)?.fir
|
||||
if (enhanced != null && enhanced !in renderedDeclarations) {
|
||||
enhanced.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += enhanced
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
else -> {
|
||||
declaration.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += declaration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
processedJavaClasses += javaClass
|
||||
}
|
||||
}.toString()
|
||||
|
||||
val expectedFile = File(javaFile.absolutePath.replace(".java", ".fir.txt"))
|
||||
KotlinTestUtils.assertEqualsToFile(expectedFile, javaFirDump)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FOREIGN_ANNOTATIONS_SOURCES_PATH = "third-party/annotations"
|
||||
}
|
||||
}
|
||||
Generated
+1648
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.BaseTransformedType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
@@ -29,5 +30,8 @@ interface FirAnnotationCall : FirCall {
|
||||
}
|
||||
}
|
||||
|
||||
val FirAnnotationCall.coneClassLikeType: ConeClassLikeType?
|
||||
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.takeIf { it !is ConeClassErrorType }
|
||||
|
||||
val FirAnnotationCall.resolvedFqName: FqName?
|
||||
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag?.classId?.asSingleFqName()
|
||||
get() = coneClassLikeType?.lookupTag?.classId?.asSingleFqName()
|
||||
|
||||
Reference in New Issue
Block a user