[FIR] Support FIR version of all-open plugin

This commit is contained in:
Dmitriy Novozhilov
2022-05-13 16:40:49 +03:00
committed by teamcity
parent 4003ca0691
commit 22ebea8174
18 changed files with 334 additions and 18 deletions
+14 -3
View File
@@ -8,6 +8,14 @@ plugins {
dependencies {
compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:fir:cones"))
compileOnly(project(":compiler:fir:tree"))
compileOnly(project(":compiler:fir:resolve"))
compileOnly(project(":compiler:fir:checkers"))
compileOnly(project(":compiler:ir.backend.common"))
compileOnly(project(":compiler:fir:entrypoint"))
compileOnly(intellijCore())
runtimeOnly(kotlinStdlib())
@@ -21,6 +29,12 @@ dependencies {
testApi(projectTests(":compiler:tests-common-new"))
testApi(projectTests(":compiler:test-infrastructure"))
testApi(projectTests(":compiler:test-infrastructure-utils"))
testApi(project(":compiler:fir:checkers"))
testRuntimeOnly(project(":compiler:fir:fir-serialization"))
testCompileOnly(project(":kotlin-reflect-api"))
testRuntimeOnly(project(":kotlin-reflect"))
testRuntimeOnly(project(":core:descriptors.runtime"))
}
sourceSets {
@@ -32,11 +46,8 @@ sourceSets {
}
runtimeJar()
sourcesJar()
javadocJar()
testsJar()
projectTest(parallel = true) {
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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.
* 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.allopen
@@ -20,10 +9,12 @@ import com.intellij.mock.MockProject
import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor.Companion.SUPPORTED_PRESETS
import org.jetbrains.kotlin.allopen.AllOpenConfigurationKeys.ANNOTATION
import org.jetbrains.kotlin.allopen.AllOpenConfigurationKeys.PRESET
import org.jetbrains.kotlin.allopen.fir.FirAllOpenExtensionRegistrar
import org.jetbrains.kotlin.compiler.plugin.*
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
object AllOpenConfigurationKeys {
val ANNOTATION: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create("annotation qualified name")
@@ -85,5 +76,9 @@ class AllOpenComponentRegistrar : ComponentRegistrar {
if (annotations.isEmpty()) return
DeclarationAttributeAltererExtension.registerExtension(project, CliAllOpenDeclarationAttributeAltererExtension(annotations))
FirExtensionRegistrar.registerExtension(project, FirAllOpenExtensionRegistrar(annotations))
}
override val supportsK2: Boolean
get() = true
}
@@ -0,0 +1,14 @@
/*
* 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.allopen.fir
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
class FirAllOpenExtensionRegistrar(val allOpenAnnotationFqNames: List<String>) : FirExtensionRegistrar() {
override fun ExtensionRegistrarContext.configurePlugin() {
+FirAllOpenStatusTransformer.getFactory(allOpenAnnotationFqNames)
}
}
@@ -0,0 +1,78 @@
/*
* 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.allopen.fir
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.copy
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
import org.jetbrains.kotlin.fir.extensions.FirStatusTransformerExtension
import org.jetbrains.kotlin.fir.extensions.FirStatusTransformerExtension.Factory
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.extensions.predicate.metaHas
import org.jetbrains.kotlin.fir.extensions.predicate.or
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
import org.jetbrains.kotlin.name.FqName
class FirAllOpenStatusTransformer(allOpenAnnotationFqNames: List<String>, session: FirSession) : FirStatusTransformerExtension(session) {
companion object {
fun getFactory(allOpenAnnotationFqNames: List<String>): Factory {
return Factory { session -> FirAllOpenStatusTransformer(allOpenAnnotationFqNames, session) }
}
}
private val annotationFqNames = allOpenAnnotationFqNames.map { FqName(it) }
private val hasPredicate = has(annotationFqNames) or metaHas(annotationFqNames)
private val cache: FirCache<FirRegularClassSymbol, Boolean, Nothing?> = session.firCachesFactory.createCache { symbol, _ ->
symbol.annotated()
}
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
register(hasPredicate)
}
override fun needTransformStatus(declaration: FirDeclaration): Boolean {
return when (declaration) {
is FirRegularClass -> declaration.classKind == ClassKind.CLASS && cache.getValue(declaration.symbol)
is FirCallableDeclaration -> {
val parentClassId = declaration.symbol.callableId.classId ?: return false
if (parentClassId.isLocal) return false
val parentClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId) as? FirRegularClassSymbol
?: return false
cache.getValue(parentClassSymbol)
}
else -> false
}
}
private fun FirRegularClassSymbol.annotated(): Boolean {
if (session.predicateBasedProvider.matches(hasPredicate, this)) return true
return resolvedSuperTypes.any {
val superSymbol = it.toRegularClassSymbol(session) ?: return@any false
cache.getValue(superSymbol)
}
}
override fun transformStatus(status: FirDeclarationStatus, declaration: FirDeclaration): FirDeclarationStatus {
return if (status.modality == null) {
status.copy(modality = Modality.OPEN)
} else {
status
}
}
}
@@ -27,6 +27,9 @@ import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2ClassicBackend
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2IrConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.runners.codegen.AbstractBytecodeListingTestBase
@@ -65,3 +68,15 @@ open class AbstractIrBytecodeListingTestForAllOpen :
override val backendFacade: Constructor<BackendFacade<IrBackendInput, BinaryArtifacts.Jvm>>
get() = ::JvmIrBackendFacade
}
open class AbstractFirBytecodeListingTestForAllOpen :
AbstractBytecodeListingTestForAllOpenBase<FirOutputArtifact, IrBackendInput>(
TargetBackend.JVM_IR, FrontendKinds.FIR
) {
override val frontendFacade: Constructor<FrontendFacade<FirOutputArtifact>>
get() = ::FirFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<FirOutputArtifact, IrBackendInput>>
get() = ::Fir2IrResultsConverter
override val backendFacade: Constructor<BackendFacade<IrBackendInput, BinaryArtifacts.Jvm>>
get() = ::JvmIrBackendFacade
}
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.allopen
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.allopen.fir.FirAllOpenExtensionRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
@@ -21,5 +23,7 @@ class AllOpenEnvironmentConfigurator(testServices: TestServices) : EnvironmentCo
project,
CliAllOpenDeclarationAttributeAltererExtension(annotations)
)
FirExtensionRegistrar.registerExtension(project, FirAllOpenExtensionRegistrar(annotations))
}
}
@@ -1,3 +1,6 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR version does not go inside bodies
// Also it's quiestionable do we even need to transform local classes and anonymous objects
annotation class AllOpen
@AllOpen
@@ -17,4 +20,4 @@ class Test {
Runnable { 1 }.run()
}
}
}
@@ -1,3 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR version does not support double-transitive annotations by design
annotation class AllOpen
@AllOpen
@@ -42,4 +44,4 @@ final class MyComponentImpl2_ShouldBeFinal : MyComponentBase() {
class MyComponentImpl3_ShouldBeOpen : MyComponentBase() {
final fun method_ShouldBeFinal() {}
}
}
@@ -0,0 +1,11 @@
annotation class AllOpen
@AllOpen
class Test {
val prop: String = ""
fun method() {}
class Nested {
fun nestedMethod() {}
}
}
@@ -0,0 +1,24 @@
@java.lang.annotation.Retention(value=RUNTIME)
@kotlin.Metadata
public annotation class AllOpen {
// source: 'nestedClass.kt'
}
@kotlin.Metadata
public final class Test$Nested {
// source: 'nestedClass.kt'
public method <init>(): void
public final method nestedMethod(): void
public final inner class Test$Nested
}
@AllOpen
@kotlin.Metadata
public class Test {
// source: 'nestedClass.kt'
private final @org.jetbrains.annotations.NotNull field prop: java.lang.String
public method <init>(): void
public @org.jetbrains.annotations.NotNull method getProp(): java.lang.String
public method method(): void
public final inner class Test$Nested
}
@@ -61,6 +61,12 @@ public class BytecodeListingTestForAllOpenGenerated extends AbstractBytecodeList
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/metaAnnotation.kt");
}
@Test
@TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/nestedClass.kt");
}
@Test
@TestMetadata("nestedInner.kt")
public void testNestedInner() throws Exception {
@@ -0,0 +1,117 @@
/*
* 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.allopen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing")
@TestDataPath("$PROJECT_ROOT")
public class FirBytecodeListingTestForAllOpenGenerated extends AbstractFirBytecodeListingTestForAllOpen {
@Test
public void testAllFilesPresentInBytecodeListing() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/allopen/allopen-cli/testData/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("allOpenOnNotClasses.kt")
public void testAllOpenOnNotClasses() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/allOpenOnNotClasses.kt");
}
@Test
@TestMetadata("alreadyOpen.kt")
public void testAlreadyOpen() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/alreadyOpen.kt");
}
@Test
@TestMetadata("annotationMembers.kt")
public void testAnnotationMembers() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/annotationMembers.kt");
}
@Test
@TestMetadata("anonymousObject.kt")
public void testAnonymousObject() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/anonymousObject.kt");
}
@Test
@TestMetadata("explicitFinal.kt")
public void testExplicitFinal() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/explicitFinal.kt");
}
@Test
@TestMetadata("metaAnnotation.kt")
public void testMetaAnnotation() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/metaAnnotation.kt");
}
@Test
@TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/nestedClass.kt");
}
@Test
@TestMetadata("nestedInner.kt")
public void testNestedInner() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/nestedInner.kt");
}
@Test
@TestMetadata("noAllOpen.kt")
public void testNoAllOpen() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/noAllOpen.kt");
}
@Test
@TestMetadata("privateMembers.kt")
public void testPrivateMembers() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/privateMembers.kt");
}
@Test
@TestMetadata("sealed.kt")
public void testSealed() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/sealed.kt");
}
@Test
@TestMetadata("severalAllOpen.kt")
public void testSeveralAllOpen() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/severalAllOpen.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/simple.kt");
}
@Test
@TestMetadata("springAnnotations.kt")
public void testSpringAnnotations() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/springAnnotations.kt");
}
@Test
@TestMetadata("superClassAnnotation.kt")
public void testSuperClassAnnotation() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/superClassAnnotation.kt");
}
}
@@ -61,6 +61,12 @@ public class IrBytecodeListingTestForAllOpenGenerated extends AbstractIrBytecode
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/metaAnnotation.kt");
}
@Test
@TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception {
runTest("plugins/allopen/allopen-cli/testData/bytecodeListing/nestedClass.kt");
}
@Test
@TestMetadata("nestedInner.kt")
public void testNestedInner() throws Exception {