Stub generation infrastructure (except for metadata generation) for KAPT+K2

This commit includes the basic Java stubs generation infrastructure and
the corresponding tests. The main entry point is called
Kapt4StubGenerator. Calls to it from production code will be added in a
separate commit.

 #KT-51982
This commit is contained in:
Pavel Mikhailovskii
2023-07-20 21:58:23 +02:00
committed by Space Team
parent ae4fab8483
commit 2002542ad2
113 changed files with 8249 additions and 34 deletions
+11
View File
@@ -13,6 +13,17 @@ dependencies {
implementation(project(":kotlin-annotation-processing-compiler"))
embedded(project(":kotlin-annotation-processing-compiler")) { isTransitive = false }
implementation(project(":analysis:analysis-api-standalone"))
embedded(project(":analysis:analysis-api-standalone")) {
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
exclude("org.jetbrains.kotlin", "kotlin-stdlib-common")
}
compileOnly(toolsJarApi())
testApiJUnit5()
testApi(projectTests(":kotlin-annotation-processing-compiler"))
testRuntimeOnly(toolsJar())
testRuntimeOnly(commonDependency("org.codehaus.woodstox:stax2-api"))
testRuntimeOnly(commonDependency("com.fasterxml:aalto-xml"))
}
optInToExperimentalCompilerApi()
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2023 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.kapt4
import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Context
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.base.kapt3.KaptOptions
import org.jetbrains.kotlin.kapt3.base.KaptContext
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
internal class Kapt4ContextForStubGeneration(
options: KaptOptions,
withJdk: Boolean,
logger: KaptLogger,
val analysisSession: KtAnalysisSession,
val classes: Iterable<KtLightClass>
) : KaptContext(options, withJdk, logger) {
internal val treeMaker = TreeMaker.instance(context) as Kapt4TreeMaker
override fun preregisterTreeMaker(context: Context) {
Kapt4TreeMaker.preRegister(context)
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.asJava.elements.KtLightParameter
import org.jetbrains.kotlin.kapt3.stubs.AbstractKDocCommentKeeper
import org.jetbrains.kotlin.psi.*
internal class Kapt4KDocCommentKeeper(context: Kapt4ContextForStubGeneration): AbstractKDocCommentKeeper<Kapt4ContextForStubGeneration>(context) {
fun saveKDocComment(tree: JCTree, psiElement: PsiElement) {
val ktElement = psiElement.extractOriginalKtDeclaration<KtDeclaration>() ?: return
if (psiElement is PsiField && ktElement is KtObjectDeclaration) {
// Do not write KDoc on object instance field
return
}
val docComment =
when {
ktElement is KtProperty -> ktElement.docComment
ktElement.docComment == null && ktElement is KtPropertyAccessor -> ktElement.property.docComment
else -> ktElement.docComment
} ?: return
if (psiElement is PsiMethod && psiElement.isConstructor && ktElement is KtClassOrObject) {
// We don't want the class comment to be duplicated on <init>()
return
}
saveKDocComment(tree, docComment)
}
}
inline fun <reified T : KtDeclaration> PsiElement.extractOriginalKtDeclaration(): T? {
// This when is needed to avoid recursion
val elementToExtract = when (this) {
is KtLightParameter -> when (kotlinOrigin) {
null -> method
else -> return kotlinOrigin as? T
}
else -> this
}
return when (elementToExtract) {
is KtLightMember<*> -> {
val origin = elementToExtract.lightMemberOrigin
origin?.auxiliaryOriginalElement ?: origin?.originalElement ?: elementToExtract.kotlinOrigin
}
is KtLightElement<*, *> -> elementToExtract.kotlinOrigin
else -> null
} as? T
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.psi.*
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.kapt3.base.stubs.KotlinPosition
import org.jetbrains.kotlin.kapt3.base.stubs.getJavacSignature
import org.jetbrains.kotlin.kapt3.stubs.KaptLineMappingCollectorBase
internal class Kapt4LineMappingCollector: KaptLineMappingCollectorBase() {
fun registerClass(lightClass: PsiClass) {
register(lightClass, lightClass.qualifiedNameWithSlashes)
}
fun registerMethod(lightClass: PsiClass, method: PsiMethod) {
register(method, lightClass.qualifiedNameWithSlashes + "#" + method.name + method.signature)
}
fun registerField(lightClass: PsiClass, field: PsiField) {
register(field, lightClass.qualifiedNameWithSlashes + "#" + field.name)
}
fun registerSignature(declaration: JCTree.JCMethodDecl, method: PsiMethod) {
signatureInfo[declaration.getJavacSignature()] = method.name + method.signature
}
fun getPosition(lightClass: PsiClass): KotlinPosition? {
return lineInfo[lightClass.qualifiedNameWithSlashes]
}
fun getPosition(lightClass: PsiClass, method: PsiMethod): KotlinPosition? =
lineInfo[lightClass.qualifiedNameWithSlashes + "#" + method.name + method.signature]
fun getPosition(lightClass: PsiClass, field: PsiField): KotlinPosition? {
return lineInfo[lightClass.qualifiedNameWithSlashes + "#" + field.name]
}
private fun register(asmNode: Any, fqName: String) {
val psiElement = (asmNode as? KtLightElement<*, *>)?.kotlinOrigin ?: return
register(fqName, psiElement)
}
private val PsiClass.qualifiedNameWithSlashes: String
get() = qualifiedNameWithDollars?.replace(".", "/") ?: "<no name provided>"
}
@@ -0,0 +1,913 @@
/*
* Copyright 2010-2023 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.
*/
@file:Suppress("UnstableApiUsage")
package org.jetbrains.kotlin.kapt4
import com.intellij.psi.*
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.code.TypeTag
import com.sun.tools.javac.parser.Tokens
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.JCTree.*
import kotlinx.kapt.KaptIgnored
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
import org.jetbrains.kotlin.base.kapt3.KaptFlag
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.kapt3.base.javac.kaptError
import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError
import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation
import org.jetbrains.kotlin.kapt3.base.util.TopLevelJava9Aware
import org.jetbrains.kotlin.kapt3.stubs.MemberData
import org.jetbrains.kotlin.kapt3.stubs.MembersPositionComparator
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.name.isOneSegmentFQN
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.calls.util.getCalleeExpressionIfAny
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import java.io.File
import javax.lang.model.element.ElementKind
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.sign
context(Kapt4ContextForStubGeneration)
internal class Kapt4StubGenerator {
private companion object {
private const val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
private const val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong()
private const val CLASS_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private const val METHOD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_NATIVE or Opcodes.ACC_STATIC or Opcodes.ACC_STRICT).toLong()
private const val FIELD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private const val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong()
private val BLACKLISTED_ANNOTATIONS = listOf(
"java.lang.Synthetic",
"synthetic.kotlin.jvm.GeneratedByJvmOverloads" // kapt3-related annotation for marking JvmOverloads-generated methods
)
private val KOTLIN_METADATA_ANNOTATION = Metadata::class.java.name
private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex()
@Suppress("UselessCallOnNotNull") // nullable toString(), KT-27724
private val JAVA_KEYWORDS = Tokens.TokenKind.values()
.filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) }
.mapTo(hashSetOf(), Any::toString)
}
private val strictMode = options[KaptFlag.STRICT]
private val stripMetadata = options[KaptFlag.STRIP_METADATA]
private val keepKdocComments = options[KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS]
private val dumpDefaultParameterValues = options[KaptFlag.DUMP_DEFAULT_PARAMETER_VALUES]
private val kdocCommentKeeper = runIf(keepKdocComments) { Kapt4KDocCommentKeeper(this@Kapt4ContextForStubGeneration) }
internal fun generateStubs(): Map<KtLightClass, KaptStub?> {
return classes.associateWith { convertTopLevelClass(it) }
}
private fun convertTopLevelClass(lightClass: KtLightClass): KaptStub? {
val ktFiles = when(lightClass) {
is KtLightClassForFacade -> lightClass.files
else -> listOfNotNull(lightClass.kotlinOrigin?.containingKtFile)
}
val lineMappings = Kapt4LineMappingCollector()
val packageName = (lightClass.parent as? PsiJavaFile)?.packageName ?: return null
val packageClause = runUnless(packageName.isBlank()) { treeMaker.FqName(packageName) }
val unresolvedQualifiersRecorder = UnresolvedQualifiersRecorder(ktFiles)
val classDeclaration = with(unresolvedQualifiersRecorder) {
convertClass(lightClass, lineMappings, packageName) ?: return null
}
val classes = JavacList.of<JCTree>(classDeclaration)
// imports should be collected after class conversion to
val imports = ktFiles.fold(JavacList.nil<JCTree>()) { acc, file ->
acc.appendList(convertImports(file, unresolvedQualifiersRecorder))
}
val topLevel = treeMaker.TopLevelJava9Aware(packageClause, imports + classes)
if (kdocCommentKeeper != null) {
topLevel.docComments = kdocCommentKeeper.getDocTable(topLevel)
}
return KaptStub(topLevel, lineMappings.serialize())
}
context(UnresolvedQualifiersRecorder)
private fun convertClass(
lightClass: PsiClass,
lineMappings: Kapt4LineMappingCollector,
packageFqName: String
): JCClassDecl? {
if (!checkIfValidTypeName(lightClass, lightClass.defaultType)) return null
val parentClass = lightClass.parent as? PsiClass
val flags = if ((parentClass?.isInterface == true || parentClass?.isAnnotationType == true) && !lightClass.isPublic)
(lightClass.accessFlags and Flags.PRIVATE.toLong().inv()) else lightClass.accessFlags
val metadata = calculateMetadata(lightClass)
val isEnum = lightClass.isEnum
val modifiers = convertModifiers(
lightClass,
flags,
if (isEnum) ElementKind.ENUM else ElementKind.CLASS,
packageFqName,
lightClass.annotations.toList(),
metadata,
)
val simpleName = lightClass.name!!
if (!isValidIdentifier(simpleName)) return null
val classSignature = parseClassSignature(lightClass)
val enumValues: JavacList<JCTree> = mapJList(lightClass.fields) { field ->
if (field !is PsiEnumConstant) return@mapJList null
val constructorArguments = lightClass.constructors.firstOrNull()?.parameters?.mapNotNull { it.type as? PsiType }.orEmpty()
val args = mapJList(constructorArguments) { convertLiteralExpression(getDefaultValue(it)) }
convertField(
field, lightClass, lineMappings, packageFqName, treeMaker.NewClass(
/* enclosing = */ null,
/* typeArgs = */ JavacList.nil(),
/* lightClass = */ treeMaker.Ident(treeMaker.name(field.name)),
/* args = */ args,
/* def = */ null
)
)
}
val fieldsPositions = mutableMapOf<JCTree, MemberData>()
val fields = mapJList<PsiField, JCTree>(lightClass.fields) { field ->
runUnless(field is PsiEnumConstant) { convertField(field, lightClass, lineMappings, packageFqName)?.also {
fieldsPositions[it] = MemberData(field.name, field.signature, lineMappings.getPosition(lightClass, field))
}
}
}
val methodsPositions = mutableMapOf<JCTree, MemberData>()
val methods = mapJList<PsiMethod, JCTree>(lightClass.methods) { method ->
if (isEnum && method.isSyntheticStaticEnumMethod()) {
return@mapJList null
}
convertMethod(method, lightClass, lineMappings, packageFqName)?.also {
methodsPositions[it] = MemberData(method.name, method.signature, lineMappings.getPosition(lightClass, method))
}
}
val nestedClasses = mapJList(lightClass.innerClasses) { innerClass ->
convertClass(innerClass, lineMappings, packageFqName)
}
lineMappings.registerClass(lightClass)
val classPosition = lineMappings.getPosition(lightClass)
val sortedFields = JavacList.from(fields.sortedWith(MembersPositionComparator(classPosition, fieldsPositions)))
val sortedMethods = JavacList.from(methods.sortedWith(MembersPositionComparator(classPosition, methodsPositions)))
return treeMaker.ClassDef(
modifiers,
treeMaker.name(simpleName),
classSignature.typeParameters,
classSignature.superClass.takeUnless { classSignature.superClassIsObject || lightClass.isEnum },
classSignature.interfaces,
JavacList.from(enumValues + sortedFields + sortedMethods + nestedClasses)
).keepKdocCommentsIfNecessary(lightClass)
}
private fun PsiMethod.isSyntheticStaticEnumMethod(): Boolean {
if (!this.isStatic) return false
return when (name) {
StandardNames.ENUM_VALUES.asString() -> parameters.isEmpty()
StandardNames.ENUM_VALUE_OF.asString() -> (parameters.singleOrNull()?.type as? PsiClassType)?.qualifiedName == "java.lang.String"
else -> false
}
}
private fun convertImports(file: KtFile, unresolvedQualifiers: UnresolvedQualifiersRecorder): JavacList<JCTree> {
if (unresolvedQualifiers.isEmpty()) return JavacList.nil()
val imports = mutableListOf<JCImport>()
val importedShortNames = mutableSetOf<String>()
// We prefer ordinary imports over aliased ones.
val sortedImportDirectives = file.importDirectives.partition { it.aliasName == null }.run { first + second }
loop@ for (importDirective in sortedImportDirectives) {
val acceptableByName = when {
importDirective.isAllUnder -> unresolvedQualifiers.simpleNames.isNotEmpty()
else -> {
val fqName = importDirective.importedFqName ?: continue
fqName.asString() in unresolvedQualifiers.qualifiedNames || fqName.shortName().identifier in unresolvedQualifiers.simpleNames
}
}
if (!acceptableByName) continue
val importedSymbols = with(analysisSession) {
val importedReference = importDirective.importedReference
?.getCalleeExpressionIfAny()
?.references
?.firstOrNull() as? KtReference
importedReference?.resolveToSymbols().orEmpty()
}
val isAllUnderClassifierImport = importDirective.isAllUnder && importedSymbols.any { it is KtClassOrObjectSymbol }
val isCallableImport = !importDirective.isAllUnder && importedSymbols.any { it is KtCallableSymbol }
val isEnumEntryImport = !importDirective.isAllUnder && importedSymbols.any { it is KtEnumEntrySymbol }
if (isAllUnderClassifierImport || isCallableImport || isEnumEntryImport) continue
// Qualified name should be valid Java fq-name
val importedFqName = importDirective.importedFqName?.takeIf { it.pathSegments().size > 1 } ?: continue
if (!isValidQualifiedName(importedFqName)) continue
val importedExpr = treeMaker.FqName(importedFqName.asString())
imports += if (importDirective.isAllUnder) {
treeMaker.Import(treeMaker.Select(importedExpr, treeMaker.nameTable.names.asterisk), false)
} else {
if (!importedShortNames.add(importedFqName.shortName().asString())) {
continue
}
treeMaker.Import(importedExpr, false)
}
}
return JavacList.from(imports)
}
private fun convertMetadataAnnotation(metadata: Metadata): JCAnnotation {
val argumentsWithNames = mapOf(
"k" to metadata.kind,
"mv" to metadata.metadataVersion.toList(),
"bv" to metadata.bytecodeVersion.toList(),
"d1" to metadata.data1.toList(),
"d2" to metadata.data2.toList(),
"xs" to metadata.extraString,
"pn" to metadata.packageName,
"xi" to metadata.extraInt,
)
val arguments = argumentsWithNames.map { (name, value) ->
val jValue = convertLiteralExpression(value)
treeMaker.Assign(treeMaker.SimpleName(name), jValue)
}
return treeMaker.Annotation(treeMaker.FqName(Metadata::class.java.canonicalName), JavacList.from(arguments))
}
context(UnresolvedQualifiersRecorder)
private fun convertAnnotation(
containingClass: PsiClass,
annotation: PsiAnnotation,
packageFqName: String
): JCAnnotation? {
val rawQualifiedName = annotation.qualifiedName ?: return null
val fqName = treeMaker.getQualifiedName(rawQualifiedName)
if (BLACKLISTED_ANNOTATIONS.any { fqName.startsWith(it) }) return null
if (stripMetadata && fqName == KOTLIN_METADATA_ANNOTATION) return null
val annotationFqName = annotation.resolveAnnotationType()?.defaultType.convertAndRecordErrors {
val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName
when {
useSimpleName -> treeMaker.FqName(fqName.substring(packageFqName.length + 1))
else -> treeMaker.FqName(fqName)
}
}
val values = mapJList<_, JCExpression>(annotation.parameterList.attributes) {
val name = it.name?.takeIf { name -> isValidIdentifier(name) } ?: return@mapJList null
val value = it.value
val expr = if (value == null) {
((it as? KtLightElementBase)?.kotlinOrigin as? KtDotQualifiedExpression)?.let { convertDotQualifiedExpression(it) }
?: return@mapJList null
} else {
convertPsiAnnotationMemberValue(containingClass, value, packageFqName)
}
treeMaker.Assign(treeMaker.SimpleName(name), expr)
}
return treeMaker.Annotation(annotationFqName, values)
}
private fun convertDotQualifiedExpression(dotQualifiedExpression: KtDotQualifiedExpression): JCExpression? {
val qualifier = dotQualifiedExpression.lastChild as? KtNameReferenceExpression ?: return null
val name = qualifier.text.takeIf { isValidIdentifier(it) } ?: "InvalidFieldName"
val lhs = when(val left = dotQualifiedExpression.firstChild) {
is KtNameReferenceExpression -> treeMaker.SimpleName(left.getReferencedName())
is KtDotQualifiedExpression -> convertDotQualifiedExpression(left) ?: return null
else -> return null
}
return treeMaker.Select(lhs, treeMaker.name(name))
}
context(UnresolvedQualifiersRecorder)
private fun convertPsiAnnotationMemberValue(
containingClass: PsiClass,
value: PsiAnnotationMemberValue,
packageFqName: String,
): JCExpression? {
return when (value) {
is PsiArrayInitializerMemberValue -> {
val arguments = mapJList(value.initializers) {
convertPsiAnnotationMemberValue(containingClass, it, packageFqName)
}
treeMaker.NewArray(null, null, arguments)
}
is PsiLiteral -> convertLiteralExpression(value.value)
is PsiClassObjectAccessExpression -> {
val type = value.operand.type
checkIfValidTypeName(containingClass, type)
treeMaker.Select(treeMaker.SimpleName(type.qualifiedName), treeMaker.name("class"))
}
is PsiAnnotation -> convertAnnotation(containingClass, value, packageFqName)
else -> treeMaker.SimpleName(value.text)
}
}
context(UnresolvedQualifiersRecorder)
private fun convertModifiers(
containingClass: PsiClass,
access: Long,
kind: ElementKind,
packageFqName: String,
allAnnotations: List<PsiAnnotation>,
metadata: Metadata?,
excludeNullabilityAnnotations: Boolean = false,
): JCModifiers {
var seenDeprecated = false
fun convertAndAdd(list: JavacList<JCAnnotation>, annotation: PsiAnnotation): JavacList<JCAnnotation> {
seenDeprecated = seenDeprecated or annotation.hasQualifiedName("java.lang.Deprecated")
if (excludeNullabilityAnnotations &&
(annotation.hasQualifiedName("org.jetbrains.annotations.NotNull") || annotation.hasQualifiedName("org.jetbrains.annotations.Nullable"))
) return list
val annotationTree = convertAnnotation(containingClass, annotation, packageFqName) ?: return list
return list.prepend(annotationTree)
}
var annotations = allAnnotations.reversed().fold(JavacList.nil(), ::convertAndAdd)
if (!seenDeprecated && isDeprecated(access)) {
val type = treeMaker.RawType(Type.getType(java.lang.Deprecated::class.java))
annotations = annotations.append(treeMaker.Annotation(type, JavacList.nil()))
}
if (metadata != null) {
annotations = annotations.prepend(convertMetadataAnnotation(metadata))
}
val flags = when (kind) {
ElementKind.ENUM -> access and CLASS_MODIFIERS and Opcodes.ACC_ABSTRACT.inv().toLong()
ElementKind.CLASS -> access and CLASS_MODIFIERS
ElementKind.METHOD -> access and METHOD_MODIFIERS
ElementKind.FIELD -> access and FIELD_MODIFIERS
ElementKind.PARAMETER -> access and PARAMETER_MODIFIERS
else -> throw IllegalArgumentException("Invalid element kind: $kind")
}
return treeMaker.Modifiers(flags, annotations)
}
class KaptStub(val file: JCCompilationUnit, private val kaptMetadata: ByteArray) {
fun writeMetadataIfNeeded(forSource: File): File {
val metadataFile = File(
forSource.parentFile,
forSource.nameWithoutExtension + KaptStubLineInformation.KAPT_METADATA_EXTENSION
)
metadataFile.writeBytes(kaptMetadata)
return metadataFile
}
}
context(UnresolvedQualifiersRecorder)
private fun convertField(
field: PsiField,
containingClass: PsiClass,
lineMappings: Kapt4LineMappingCollector,
packageFqName: String,
explicitInitializer: JCExpression? = null
): JCVariableDecl? {
val fieldAnnotations = field.annotations.asList()
if (isIgnored(fieldAnnotations)) return null
val access = field.accessFlags
val modifiers = convertModifiers(
containingClass,
access, ElementKind.FIELD, packageFqName,
fieldAnnotations,
metadata = null
)
val name = field.name
if (!isValidIdentifier(name)) return null
val type = field.type
if (!checkIfValidTypeName(containingClass, type)) return null
// Enum type must be an identifier (Javac requirement)
val typeExpression = if (isEnum(access)) {
treeMaker.SimpleName(treeMaker.getQualifiedName(type as PsiClassType).substringAfterLast('.'))
} else {
type.convertAndRecordErrors()
}
lineMappings.registerField(containingClass, field)
val skip = field.navigationElement is KtParameter && !dumpDefaultParameterValues
val initializer =
explicitInitializer ?: convertPropertyInitializer(if (skip) null else field.initializer, field.type, field.isFinal)
return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer).keepKdocCommentsIfNecessary(field)
}
private fun convertPropertyInitializer(propertyInitializer: PsiExpression?, type: PsiType, usedDefault: Boolean): JCExpression? {
if (propertyInitializer != null || usedDefault) {
return when (propertyInitializer) {
is PsiLiteralExpression -> {
val rawValue = propertyInitializer.value
val rawNumberValue = rawValue as? Number
val actualValue = when (type) {
PsiType.BYTE -> rawNumberValue?.toByte()
PsiType.SHORT -> rawNumberValue?.toShort()
PsiType.INT -> rawNumberValue?.toInt()
PsiType.LONG -> rawNumberValue?.toLong()
PsiType.FLOAT -> rawNumberValue?.toFloat()
PsiType.DOUBLE -> rawNumberValue?.toDouble()
else -> null
} ?: rawValue
convertValueOfPrimitiveTypeOrString(actualValue)
}
is PsiPrefixExpression -> {
assert(propertyInitializer.operationSign.tokenType == JavaTokenType.MINUS)
val operand = convertPropertyInitializer(propertyInitializer.operand, type, usedDefault)
if (operand.toString().startsWith("-")) operand // overflow
else treeMaker.Unary(Tag.NEG, operand)
}
is PsiBinaryExpression -> {
assert(propertyInitializer.operationSign.tokenType == JavaTokenType.DIV)
treeMaker.Binary(
Tag.DIV,
convertPropertyInitializer(propertyInitializer.lOperand, type, false),
convertPropertyInitializer(propertyInitializer.rOperand, type, false)
)
}
is PsiReferenceExpression ->
when (val resolved = propertyInitializer.resolve()) {
is PsiEnumConstant ->
treeMaker.FqName(resolved.containingClass!!.qualifiedName + "." + resolved.name)
else -> null
}
is PsiArrayInitializerExpression ->
treeMaker.NewArray(
null, JavacList.nil(),
mapJList(propertyInitializer.initializers) { convertPropertyInitializer(it, type.deepComponentType, false) }
)
else -> convertLiteralExpression(getDefaultValue(type))
}
}
return null
}
private fun convertLiteralExpression(value: Any?): JCExpression {
fun convertDeeper(value: Any?) = convertLiteralExpression(value)
convertValueOfPrimitiveTypeOrString(value)?.let { return it }
return when (value) {
null -> treeMaker.Literal(TypeTag.BOT, null)
is ByteArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is BooleanArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is CharArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is ShortArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is IntArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is LongArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is FloatArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is DoubleArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable(), ::convertDeeper))
is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName])
assert(value.size == 2)
val enumType = Type.getType(value[0] as String)
val valueName = (value[1] as String).takeIf { isValidIdentifier(it) } ?: run {
compiler.log.report(kaptError("'${value[1]}' is an invalid Java enum value name"))
"InvalidFieldName"
}
treeMaker.Select(treeMaker.RawType(enumType), treeMaker.name(valueName))
}
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value, ::convertDeeper))
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value::class.java.canonicalName})")
}
}
private fun getDefaultValue(type: PsiType): Any? = when (type) {
PsiType.BYTE -> 0
PsiType.BOOLEAN -> false
PsiType.CHAR -> '\u0000'
PsiType.SHORT -> 0
PsiType.INT -> 0
PsiType.LONG -> 0L
PsiType.FLOAT -> 0.0F
PsiType.DOUBLE -> 0.0
else -> null
}
private fun convertValueOfPrimitiveTypeOrString(value: Any?): JCExpression? {
fun specialFpValueNumerator(value: Double): Double = if (value.isNaN()) 0.0 else 1.0 * value.sign
val convertedValue = when (value) {
is Char -> treeMaker.Literal(TypeTag.CHAR, value.code)
is Byte -> treeMaker.TypeCast(treeMaker.TypeIdent(TypeTag.BYTE), treeMaker.Literal(TypeTag.INT, value.toInt()))
is Short -> treeMaker.TypeCast(treeMaker.TypeIdent(TypeTag.SHORT), treeMaker.Literal(TypeTag.INT, value.toInt()))
is Boolean, is Int, is Long, is String -> treeMaker.Literal(value)
is Float -> when {
value.isFinite() -> treeMaker.Literal(value)
else -> treeMaker.Binary(
Tag.DIV,
treeMaker.Literal(specialFpValueNumerator(value.toDouble()).toFloat()),
treeMaker.Literal(0.0F)
)
}
is Double -> when {
value.isFinite() -> treeMaker.Literal(value)
else -> treeMaker.Binary(Tag.DIV, treeMaker.Literal(specialFpValueNumerator(value)), treeMaker.Literal(0.0))
}
null -> treeMaker.Literal(TypeTag.BOT, null)
else -> null
}
return convertedValue
}
context(UnresolvedQualifiersRecorder)
private fun convertMethod(
method: PsiMethod,
containingClass: PsiClass,
lineMappings: Kapt4LineMappingCollector,
packageFqName: String,
): JCMethodDecl? {
if (isIgnored(method.annotations.asList())) return null
val isConstructor = method.isConstructor
val name = method.name
if (!isConstructor && !isValidIdentifier(name)) return null
val returnType = method.returnType ?: PsiType.VOID
val modifiers = convertModifiers(
containingClass,
if (containingClass.isEnum && isConstructor)
(method.accessFlags and VISIBILITY_MODIFIERS.inv())
else
method.accessFlags,
ElementKind.METHOD,
packageFqName,
method.annotations.toList(),
metadata = null,
excludeNullabilityAnnotations = returnType == PsiType.VOID
)
if (method.hasModifierProperty(PsiModifier.DEFAULT)) {
modifiers.flags = modifiers.flags or Flags.DEFAULT
}
val parametersInfo = method.getParametersInfo()
if (!checkIfValidTypeName(containingClass, returnType)
|| parametersInfo.any { !checkIfValidTypeName(containingClass, it.type) }
) {
return null
}
@Suppress("NAME_SHADOWING")
val jParameters = mapJListIndexed(parametersInfo) { index, info ->
val lastParameter = index == parametersInfo.lastIndex
val isArrayType = info.type is PsiArrayType
val varargs = if (lastParameter && isArrayType && method.isVarArgs) Flags.VARARGS else 0L
val modifiers = convertModifiers(
containingClass,
Flags.PARAMETER or varargs, // Kapt never marked method parameters as "final"
ElementKind.PARAMETER,
packageFqName,
info.annotations,
metadata = null
)
val defaultName = info.name
val name = when {
isValidIdentifier(defaultName) -> defaultName
defaultName == SpecialNames.IMPLICIT_SET_PARAMETER.asString() -> "p0"
else -> "p${index}_${info.name.hashCode().ushr(1)}"
}
val type = info.type.convertAndRecordErrors()
treeMaker.VarDef(modifiers, treeMaker.name(name), type, null)
}
val jTypeParameters = mapJList(method.typeParameters) { convertTypeParameter(it) }
val jExceptionTypes = mapJList(method.throwsTypes) { treeMaker.TypeWithArguments(it as PsiType) }
val jReturnType = runUnless(isConstructor) {
returnType.convertAndRecordErrors()
}
val defaultValue = (method as? PsiAnnotationMethod)?.defaultValue?.let {
convertPsiAnnotationMemberValue(containingClass, it, packageFqName)
}
val body = if (defaultValue != null) {
null
} else if (method.isAbstract or (modifiers.flags and Flags.ABSTRACT.toLong() != 0L)) {
null
} else if (isConstructor && containingClass.isEnum) {
treeMaker.Block(0, JavacList.nil())
} else if (isConstructor) {
val superConstructor = containingClass.superClass?.constructors?.firstOrNull { !it.isPrivate }
val superClassConstructorCall = if (superConstructor != null) {
val args = mapJList(superConstructor.parameterList.parameters) { param ->
convertLiteralExpression(getDefaultValue(param.type))
}
val call = treeMaker.Apply(JavacList.nil(), treeMaker.SimpleName("super"), args)
JavacList.of<JCStatement>(treeMaker.Exec(call))
} else {
JavacList.nil()
}
treeMaker.Block(0, superClassConstructorCall)
} else if (returnType == PsiType.VOID) {
treeMaker.Block(0, JavacList.nil())
} else {
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(returnType)))
treeMaker.Block(0, JavacList.of(returnStatement))
}
lineMappings.registerMethod(containingClass, method)
return treeMaker.MethodDef(
modifiers, treeMaker.name(name), jReturnType, jTypeParameters,
jParameters, jExceptionTypes,
body, defaultValue
).keepSignature(lineMappings, method).keepKdocCommentsIfNecessary(method)
}
private fun JCMethodDecl.keepSignature(lineMappings: Kapt4LineMappingCollector, method: PsiMethod): JCMethodDecl {
lineMappings.registerSignature(this, method)
return this
}
private fun <T : JCTree> T.keepKdocCommentsIfNecessary(element: PsiElement): T {
kdocCommentKeeper?.saveKDocComment(this, element)
return this
}
private fun isIgnored(annotations: List<PsiAnnotation>?): Boolean {
val kaptIgnoredAnnotationFqName = KaptIgnored::class.java.canonicalName
return annotations?.any { it.hasQualifiedName(kaptIgnoredAnnotationFqName) } ?: false
}
context(UnresolvedQualifiersRecorder)
private fun checkIfValidTypeName(
containingClass: PsiClass,
type: PsiType
): Boolean {
when (type) {
is PsiArrayType -> return checkIfValidTypeName(containingClass, type.componentType)
is PsiPrimitiveType -> return true
}
val internalName = type.qualifiedName
// Ignore type names with Java keywords in it
if (internalName.split('/', '.').any { it in JAVA_KEYWORDS }) {
if (strictMode) {
reportKaptError(
"Can't generate a stub for '${internalName}'.",
"Type name '${type.qualifiedName}' contains a Java keyword."
)
}
return false
}
val clazz = type.resolvedClass ?: return true
if (doesInnerClassNameConflictWithOuter(clazz)) {
if (strictMode) {
reportKaptError(
"Can't generate a stub for '${clazz.qualifiedNameWithDollars}'.",
"Its name '${clazz.name}' is the same as one of the outer class names.",
"Java forbids it. Please change one of the class names."
)
}
return false
}
reportIfIllegalTypeUsage(containingClass, type)
return true
}
private fun findContainingClassNode(clazz: PsiClass): PsiClass? {
return clazz.parent as? PsiClass
}
// Java forbids outer and inner class names to be the same. Check if the names are different
private tailrec fun doesInnerClassNameConflictWithOuter(
clazz: PsiClass,
outerClass: PsiClass? = findContainingClassNode(clazz)
): Boolean {
if (outerClass == null) return false
if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true
// Try to find the containing class for outerClassNode (to check the whole tree recursively)
val containingClassForOuterClass = findContainingClassNode(outerClass) ?: return false
return doesInnerClassNameConflictWithOuter(clazz, containingClassForOuterClass)
}
context(UnresolvedQualifiersRecorder)
private fun reportIfIllegalTypeUsage(
containingClass: PsiClass,
type: PsiType
) {
val typeName = type.simpleNameOrNull ?: return
if (typeName !in reportedTypes && typeName in importsFromRoot) {
reportedTypes += typeName
val msg = "${containingClass.qualifiedName}: Can't reference type '${typeName}' from default package in Java stub."
if (strictMode) reportKaptError(msg)
else logger.warn(msg)
}
}
context(UnresolvedQualifiersRecorder)
@OptIn(ExperimentalContracts::class)
private inline fun PsiType?.convertAndRecordErrors(
ifNonError: () -> JCExpression = { treeMaker.TypeWithArguments(this!!) }
): JCExpression {
contract {
callsInPlace(ifNonError, InvocationKind.EXACTLY_ONCE)
}
this?.recordErrorTypes()
return ifNonError()
}
context(UnresolvedQualifiersRecorder)
private fun PsiType.recordErrorTypes() {
if (this is PsiEllipsisType) {
this.componentType.recordErrorTypes()
return
}
if (qualifiedNameOrNull == null) {
recordUnresolvedQualifier(qualifiedName)
}
when (this) {
is PsiClassType -> typeArguments().forEach { (it as? PsiType)?.recordErrorTypes() }
is PsiArrayType -> componentType.recordErrorTypes()
}
}
private fun isValidQualifiedName(name: FqName) = name.pathSegments().all { isValidIdentifier(it.asString()) }
private fun isValidIdentifier(name: String): Boolean {
if (name in JAVA_KEYWORDS) return false
return !(name.isEmpty()
|| !Character.isJavaIdentifierStart(name[0])
|| name.drop(1).any { !Character.isJavaIdentifierPart(it) })
}
private class ClassGenericSignature(
val typeParameters: JavacList<JCTypeParameter>,
val superClass: JCExpression,
val interfaces: JavacList<JCExpression>,
val superClassIsObject: Boolean
)
context(UnresolvedQualifiersRecorder)
private fun parseClassSignature(psiClass: PsiClass): ClassGenericSignature {
val superClasses = mutableListOf<JCExpression>()
val superInterfaces = mutableListOf<JCExpression>()
val superPsiClasses = psiClass.extendsListTypes.toList()
val superPsiInterfaces = psiClass.implementsListTypes.toList()
fun addSuperType(superType: PsiClassType, destination: MutableList<JCExpression>) {
if (psiClass.isAnnotationType && superType.qualifiedName == "java.lang.annotation.Annotation") return
destination += superType.convertAndRecordErrors()
}
var superClassIsObject = false
superPsiClasses.forEach {
addSuperType(it, superClasses)
superClassIsObject = superClassIsObject || it.qualifiedNameOrNull == "java.lang.Object"
}
for (superInterface in superPsiInterfaces) {
if (superInterface.qualifiedName.startsWith("kotlin.collections.")) continue
addSuperType(superInterface, superInterfaces)
}
val jcTypeParameters = mapJList(psiClass.typeParameters) { convertTypeParameter(it) }
val jcSuperClass = superClasses.firstOrNull().takeUnless { psiClass.isInterface } ?: createJavaLangObjectType().also {
superClassIsObject = true
}
val jcInterfaces = JavacList.from(if (psiClass.isInterface) superClasses else superInterfaces)
return ClassGenericSignature(jcTypeParameters, jcSuperClass, jcInterfaces, superClassIsObject)
}
private fun createJavaLangObjectType(): JCExpression {
return treeMaker.FqName("java.lang.Object")
}
context(UnresolvedQualifiersRecorder)
private fun convertTypeParameter(typeParameter: PsiTypeParameter): JCTypeParameter {
val classBounds = mutableListOf<JCExpression>()
val interfaceBounds = mutableListOf<JCExpression>()
val bounds = typeParameter.bounds
for (bound in bounds) {
val boundType = bound as? PsiType ?: continue
val jBound = boundType.convertAndRecordErrors()
if (boundType.resolvedClass?.isInterface == false) {
classBounds += jBound
} else {
interfaceBounds += jBound
}
}
if (classBounds.isEmpty() && interfaceBounds.isEmpty()) {
classBounds += createJavaLangObjectType()
}
return treeMaker.TypeParameter(treeMaker.name(typeParameter.name!!), JavacList.from(classBounds + interfaceBounds))
}
private class UnresolvedQualifiersRecorder(ktFiles: Iterable<KtFile>) {
val importsFromRoot: Set<String> by lazy {
val importsFromRoot =
ktFiles
.flatMap { it.importDirectives }
.filter { !it.isAllUnder }
.mapNotNull { im -> im.importPath?.fqName?.takeIf { it.isOneSegmentFQN() } }
importsFromRoot.mapTo(mutableSetOf()) { it.asString() }
}
private val _qualifiedNames = mutableSetOf<String>()
private val _simpleNames = mutableSetOf<String>()
val reportedTypes = mutableSetOf<String>()
val qualifiedNames: Set<String>
get() = _qualifiedNames
val simpleNames: Set<String>
get() = _simpleNames
fun isEmpty(): Boolean {
return simpleNames.isEmpty()
}
fun recordUnresolvedQualifier(qualifier: String) {
val separated = qualifier.split(".")
if (separated.size > 1) {
_qualifiedNames += qualifier
_simpleNames += separated.first()
} else {
_simpleNames += qualifier
}
}
}
@Suppress("UNUSED_PARAMETER")
private fun calculateMetadata(lightClass: PsiClass): Metadata? {
if (stripMetadata) return null
return Metadata() // TODO: calculate me
}
}
@@ -0,0 +1,141 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.psi.*
import com.sun.tools.javac.code.BoundKind
import com.sun.tools.javac.code.TypeTag
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Name
import com.sun.tools.javac.util.Names
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type.*
internal class Kapt4TreeMaker(
context: Context
) : TreeMaker(context) {
val nameTable: Name.Table = Names.instance(context).table
@Suppress("FunctionName")
fun RawType(type: Type): JCTree.JCExpression {
convertBuiltinType(type)?.let { return it }
if (type.sort == ARRAY) {
return TypeArray(RawType(AsmUtil.correctElementType(type)))
}
return FqName(type.internalName)
}
@Suppress("FunctionName")
private fun RawType(type: PsiType): JCTree.JCExpression {
return when (type) {
is PsiArrayType -> TypeArray(RawType(type.componentType))
is PsiWildcardType -> Wildcard(TypeBoundKind(BoundKind.UNBOUND), null)
else -> FqName(type.qualifiedName)
}
}
@Suppress("FunctionName")
fun TypeWithArguments(type: PsiType): JCTree.JCExpression {
return when (type) {
is PsiArrayType -> TypeArray(TypeWithArguments(type.componentType))
is PsiClassType -> {
val correctedType = if (isErroneous(type)) type.rawType() else type
SimpleName(correctedType.canonicalText.replace('$', '.'))
} // TODO: Produce a proper expression, see KT-60821
is PsiWildcardType -> {
val argumentType = type.bound?.let { TypeWithArguments(it) }
when {
type.isExtends -> Wildcard(TypeBoundKind(BoundKind.EXTENDS), argumentType)
type.isSuper -> Wildcard(TypeBoundKind(BoundKind.SUPER), argumentType)
else -> Wildcard(TypeBoundKind(BoundKind.UNBOUND), argumentType)
}
}
else -> RawType(type)
}
}
private fun isErroneous(type: PsiType): Boolean {
if (type.canonicalText == StandardNames.NON_EXISTENT_CLASS.asString()) return true
if (type is PsiClassType) return type.parameters.any { isErroneous(it) }
return false
}
@Suppress("FunctionName")
fun FqName(internalOrFqName: String): JCTree.JCExpression {
val path = getQualifiedName(internalOrFqName).convertSpecialFqName().split('.')
assert(path.isNotEmpty())
return FqName(path)
}
@Suppress("FunctionName")
private fun FqName(path: List<String>): JCTree.JCExpression {
if (path.size == 1) return SimpleName(path.single())
var expr = Select(SimpleName(path[0]), name(path[1]))
for (index in 2..path.lastIndex) {
expr = Select(expr, name(path[index]))
}
return expr
}
fun getQualifiedName(type: PsiClassType): String {
val klass = type.resolve() ?: return getQualifiedName(type.qualifiedName)
return getQualifiedName(klass)
}
private fun getQualifiedName(type: PsiClass): String = getQualifiedName(type.qualifiedName!!)
fun getSimpleName(clazz: PsiClass): String = clazz.name!!
fun getQualifiedName(internalName: String): String {
val nameWithDots = internalName.replace('/', '.')
// This is a top-level class
if ('$' !in nameWithDots) return nameWithDots
return nameWithDots.replace('$', '.')
}
private fun String.convertSpecialFqName(): String {
// Hard-coded in ImplementationBodyCodegen, KOTLIN_MARKER_INTERFACES
if (this == "kotlin.jvm.internal.markers.KMutableMap\$Entry") {
return replace('$', '.')
}
return this
}
private fun convertBuiltinType(type: Type): JCTree.JCExpression? {
val typeTag = when (type) {
BYTE_TYPE -> TypeTag.BYTE
BOOLEAN_TYPE -> TypeTag.BOOLEAN
CHAR_TYPE -> TypeTag.CHAR
SHORT_TYPE -> TypeTag.SHORT
INT_TYPE -> TypeTag.INT
LONG_TYPE -> TypeTag.LONG
FLOAT_TYPE -> TypeTag.FLOAT
DOUBLE_TYPE -> TypeTag.DOUBLE
VOID_TYPE -> TypeTag.VOID
else -> null
} ?: return null
return TypeIdent(typeTag)
}
@Suppress("FunctionName")
fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name))
fun name(name: String): Name = nameTable.fromString(name)
companion object {
internal fun preRegister(context: Context) {
context.put(treeMakerKey, Context.Factory { Kapt4TreeMaker(it) })
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2023 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.
*/
@file:Suppress("UnstableApiUsage")
package org.jetbrains.kotlin.kapt4
import com.intellij.psi.JvmPsiConversionHelper
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
internal class ParameterInfo(
val name: String,
val type: PsiType,
val annotations: List<PsiAnnotation>,
)
internal fun PsiMethod.getParametersInfo(): List<ParameterInfo> {
val typeConverter = JvmPsiConversionHelper.getInstance(project)
return this.parameterList.parameters.map {
ParameterInfo(it.name, typeConverter.convertType(it.type), it.annotations.asList())
}
}
@@ -0,0 +1,229 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.lang.jvm.JvmModifier
import com.intellij.psi.*
import com.intellij.psi.util.ClassUtil
import com.intellij.psi.util.PsiTypesUtil
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.org.objectweb.asm.Opcodes
internal val PsiModifierListOwner.isPublic: Boolean get() = hasModifier(JvmModifier.PUBLIC)
internal val PsiModifierListOwner.isPrivate: Boolean get() = hasModifier(JvmModifier.PRIVATE)
internal val PsiModifierListOwner.isProtected: Boolean get() = hasModifier(JvmModifier.PROTECTED)
internal val PsiModifierListOwner.isFinal: Boolean get() = hasModifier(JvmModifier.FINAL)
internal val PsiModifierListOwner.isAbstract: Boolean get() = hasModifier(JvmModifier.ABSTRACT)
internal val PsiModifierListOwner.isStatic: Boolean get() = hasModifier(JvmModifier.STATIC)
internal val PsiModifierListOwner.isVolatile: Boolean get() = hasModifier(JvmModifier.VOLATILE)
internal val PsiModifierListOwner.isSynchronized: Boolean get() = hasModifier(JvmModifier.SYNCHRONIZED)
internal val PsiModifierListOwner.isNative: Boolean get() = hasModifier(JvmModifier.NATIVE)
internal val PsiModifierListOwner.isStrict: Boolean get() = hasModifier(JvmModifier.STRICTFP)
internal val PsiModifierListOwner.isTransient: Boolean get() = hasModifier(JvmModifier.TRANSIENT)
internal typealias JavacList<T> = com.sun.tools.javac.util.List<T>
internal inline fun <T, R> mapJList(values: Array<T>?, f: (T) -> R?): JavacList<R> {
return mapJList(values?.asList(), f)
}
internal inline fun <T, R> mapJList(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
if (values == null) return JavacList.nil()
var result = JavacList.nil<R>()
for (item in values) {
f(item)?.let { result = result.append(it) }
}
return result
}
internal inline fun <T, R> mapJListIndexed(values: Iterable<T>?, f: (Int, T) -> R?): JavacList<R> {
if (values == null) return JavacList.nil()
var result = JavacList.nil<R>()
values.forEachIndexed { index, item ->
f(index, item)?.let { result = result.append(it) }
}
return result
}
internal operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
return this.appendList(other)
}
internal val PsiMethod.signature: String
get() = ClassUtil.getAsmMethodSignature(this)
internal val PsiField.signature: String
get() = getAsmFieldSignature(this)
private fun getAsmFieldSignature(field: PsiField): String {
return ClassUtil.getBinaryPresentation(field.type)
}
internal val PsiType.qualifiedName: String
get() = qualifiedNameOrNull ?: canonicalText.replace("""<.*>""".toRegex(), "")
internal val PsiType.qualifiedNameOrNull: String?
get() {
if (this is PsiPrimitiveType) return name
if (this is PsiWildcardType) return this.bound?.qualifiedNameOrNull
return when (val resolvedClass = resolvedClass) {
is PsiTypeParameter -> resolvedClass.name
else -> resolvedClass?.qualifiedName
}
}
internal val PsiType.simpleNameOrNull: String?
get() {
if (this is PsiPrimitiveType) return name
return when (val resolvedClass = resolvedClass) {
is PsiTypeParameter -> resolvedClass.name
else -> resolvedClass?.name
}
}
internal val PsiClass.defaultType: PsiType
get() = PsiTypesUtil.getClassType(this)
internal val PsiType.resolvedClass: PsiClass?
get() = (this as? PsiClassType)?.resolve()
internal val PsiModifierListOwner.accessFlags: Long
get() = when (this) {
is PsiClass -> computeClassAccessFlags(this)
is PsiMethod -> computeMethodAccessFlags(this)
is PsiField -> computeFieldAccessFlags(this)
else -> 0
}.toLong()
private fun computeCommonAccessFlags(declaration: PsiModifierListOwner): Int {
/*
* int ACC_STATIC = 0x0008; // field, method; class isn't mentioned but actually used
* int ACC_PUBLIC = 0x0001; // class, field, method
* int ACC_PRIVATE = 0x0002; // class, field, method
* int ACC_PROTECTED = 0x0004; // class, field, method
* int ACC_FINAL = 0x0010; // class, field, method, parameter
* int ACC_DEPRECATED = 0x20000; // class, field, method
*/
var access = 0
val visibilityFlag = when {
declaration.isPublic -> Opcodes.ACC_PUBLIC
declaration.isPrivate -> Opcodes.ACC_PRIVATE
declaration.isProtected -> Opcodes.ACC_PROTECTED
else -> 0
}
access = access or visibilityFlag
if (declaration.isFinal) {
access = access or Opcodes.ACC_FINAL
}
if (declaration.annotations.any { it.hasQualifiedName(StandardNames.FqNames.deprecated.asString()) }) {
access = access or Opcodes.ACC_DEPRECATED
}
if (declaration.isStatic) {
access = access or Opcodes.ACC_STATIC
}
return access
}
private fun computeClassAccessFlags(klass: PsiClass): Int {
/*
* int ACC_INTERFACE = 0x0200; // class
* int ACC_ABSTRACT = 0x0400; // class, method
* int ACC_ANNOTATION = 0x2000; // class
* int ACC_ENUM = 0x4000; // class(?) field inner
* int ACC_RECORD = 0x10000; // class
*/
var access = computeCommonAccessFlags(klass)
val classKindFlag = when {
klass.isInterface -> Opcodes.ACC_INTERFACE
klass.isEnum -> {
// enum can not be final
access = access and Opcodes.ACC_FINAL.inv()
Opcodes.ACC_ENUM
}
klass.isRecord -> Opcodes.ACC_RECORD
else -> 0
}
access = access or classKindFlag
if (klass.isAnnotationType) {
access = access or Opcodes.ACC_ANNOTATION
}
if (klass.isAbstract) {
access = access or Opcodes.ACC_ABSTRACT
}
return access
}
private fun computeMethodAccessFlags(method: PsiMethod): Int {
/*
* int ACC_SYNCHRONIZED = 0x0020; // method
* int ACC_VARARGS = 0x0080; // method
* int ACC_NATIVE = 0x0100; // method
* int ACC_ABSTRACT = 0x0400; // class, method
* int ACC_STRICT = 0x0800; // method
*/
var access = computeCommonAccessFlags(method)
if (method.isSynchronized) {
access = access or Opcodes.ACC_SYNCHRONIZED
}
if (method.isVarArgs) {
access = access or Opcodes.ACC_VARARGS
}
if (method.isNative) {
access = access or Opcodes.ACC_NATIVE
}
if (method.isAbstract) {
access = access or Opcodes.ACC_ABSTRACT
}
if (method.isStrict) {
access = access or Opcodes.ACC_STRICT
}
return access
}
private fun computeFieldAccessFlags(field: PsiField): Int {
/*
* int ACC_VOLATILE = 0x0040; // field
* int ACC_TRANSIENT = 0x0080; // field
* int ACC_ENUM = 0x4000; // class(?) field inner
*/
var access = computeCommonAccessFlags(field)
if (field.isVolatile) {
access = access or Opcodes.ACC_VOLATILE
}
if (field.isTransient) {
access = access or Opcodes.ACC_TRANSIENT
}
if (field is PsiEnumConstant) {
access = access or Opcodes.ACC_ENUM
}
return access
}
internal val PsiClass.qualifiedNameWithDollars: String?
get() {
val packageName = PsiUtil.getPackageName(this) ?: return null
if (packageName.isBlank()) {
return qualifiedName?.replace(".", "$") ?: return null
}
val qualifiedName = this.qualifiedName ?: return null
val className = qualifiedName.substringAfter("$packageName.")
val classNameWithDollars = className.replace(".", "$")
return "$packageName.$classNameWithDollars"
}
private const val LONG_DEPRECATED = Opcodes.ACC_DEPRECATED.toLong()
private const val LONG_ENUM = Opcodes.ACC_ENUM.toLong()
internal fun isDeprecated(access: Long) = (access and LONG_DEPRECATED) != 0L
internal fun isEnum(access: Long) = (access and LONG_ENUM) != 0L
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2023 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.kapt4
import org.jetbrains.kotlin.kapt3.test.*
import org.jetbrains.kotlin.kapt3.test.KaptTestDirectives.MAP_DIAGNOSTIC_LOCATIONS
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives.WITH_STDLIB
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
open class AbstractKotlinKapt4ContextTest : AbstractKotlinKapt4ContextTestBase(TargetBackend.JVM_IR)
abstract class AbstractKotlinKapt4ContextTestBase(
targetBackend: TargetBackend
) : AbstractKotlinCompilerWithTargetBackendTest(targetBackend) {
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
frontend = FrontendKinds.FIR
targetPlatform = JvmPlatforms.defaultJvmPlatform
dependencyKind = DependencyKind.Binary
}
defaultDirectives {
+MAP_DIAGNOSTIC_LOCATIONS
+WITH_STDLIB
}
useConfigurators(
::CommonEnvironmentConfigurator,
::JvmEnvironmentConfigurator,
::KaptEnvironmentConfigurator,
::Kapt4EnvironmentConfigurator,
)
facadeStep(::Kapt4Facade)
handlersStep(Kapt4ContextBinaryArtifact.Kind) {
useHandlers(::Kapt4Handler)
}
useAfterAnalysisCheckers(::TemporaryKapt4Suppressor)
}
}
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2023 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.kapt4
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
class Kapt4EnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
override fun provideAdditionalAnalysisFlags(
directives: RegisteredDirectives,
languageVersion: LanguageVersion,
): Map<AnalysisFlag<*>, Any?> = mapOf(
JvmAnalysisFlags.generatePropertyAnnotationsMethods to true,
JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ALL_INCOMPATIBLE
)
override val directiveContainers: List<DirectivesContainer> = listOf(Kapt4TestDirectives)
}
@@ -0,0 +1,114 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.lifetime.KtReadActionConfinementLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.base.kapt3.KaptOptions
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
import org.jetbrains.kotlin.kapt3.test.KaptMessageCollectorProvider
import org.jetbrains.kotlin.kapt3.test.kaptOptionsProvider
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.*
import java.io.File
internal class Kapt4Facade(private val testServices: TestServices) :
AbstractTestFacade<ResultingArtifact.Source, Kapt4ContextBinaryArtifact>() {
override val inputKind: TestArtifactKind<ResultingArtifact.Source>
get() = SourcesKind
override val outputKind: TestArtifactKind<Kapt4ContextBinaryArtifact>
get() = Kapt4ContextBinaryArtifact.Kind
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::KaptMessageCollectorProvider))
override fun transform(module: TestModule, inputArtifact: ResultingArtifact.Source): Kapt4ContextBinaryArtifact {
val configurationProvider = testServices.compilerConfigurationProvider
val configuration = configurationProvider.getCompilerConfiguration(module)
configuration.addKotlinSourceRoots(module.files.filter { it.isKtFile }.map { it.realFile().absolutePath })
val options = testServices.kaptOptionsProvider[module]
val (context, stubMap) = run(
configuration,
options,
testServices.applicationDisposableProvider.getApplicationRootDisposable(),
configurationProvider.testRootDisposable
)
return Kapt4ContextBinaryArtifact(context, stubMap.values.filterNotNull())
}
private fun TestFile.realFile(): File {
return testServices.sourceFileProvider.getRealFileForSourceFile(this)
}
override fun shouldRunAnalysis(module: TestModule): Boolean {
return true
}
}
@OptIn(KtAnalysisApiInternals::class)
private fun run(
configuration: CompilerConfiguration,
options: KaptOptions,
applicationDisposable: Disposable,
projectDisposable: Disposable,
): Pair<Kapt4ContextForStubGeneration, Map<KtLightClass, Kapt4StubGenerator.KaptStub?>> {
val standaloneAnalysisAPISession = buildStandaloneAnalysisAPISession(applicationDisposable, projectDisposable) {
(project as MockProject).registerService(
KtLifetimeTokenProvider::class.java,
KtReadActionConfinementLifetimeTokenProvider::class.java
)
@Suppress("DEPRECATION")
buildKtModuleProviderByCompilerConfiguration(configuration)
}
val (module, psiFiles) = standaloneAnalysisAPISession.modulesWithFiles.entries.single()
val ktFiles = psiFiles.filterIsInstance<KtFile>()
val lightClasses = buildSet {
ktFiles.flatMapTo(this) { file ->
file.children.filterIsInstance<KtClassOrObject>().mapNotNull {
it.toLightClass()
}
}
ktFiles.mapNotNullTo(this) { ktFile -> ktFile.findFacadeClass() }.distinct()
}
return KtAnalysisSessionProvider.getInstance(module.project).analyze(module) {
val context = Kapt4ContextForStubGeneration(
options,
withJdk = false,
WriterBackedKaptLogger(isVerbose = false),
this@analyze,
lightClasses
)
val generator = with(context) { Kapt4StubGenerator() }
context to generator.generateStubs()
}
}
internal data class Kapt4ContextBinaryArtifact(
internal val kaptContext: Kapt4ContextForStubGeneration,
internal val kaptStubs: List<Kapt4StubGenerator.KaptStub>
) : ResultingArtifact.Binary<Kapt4ContextBinaryArtifact>() {
object Kind : BinaryKind<Kapt4ContextBinaryArtifact>("KaptArtifact")
override val kind: BinaryKind<Kapt4ContextBinaryArtifact>
get() = Kind
}
@@ -0,0 +1,177 @@
/*
* Copyright 2010-2023 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.kapt4
import com.intellij.openapi.util.text.StringUtil
import com.sun.tools.javac.comp.CompileStates
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.util.JCDiagnostic
import com.sun.tools.javac.util.List
import com.sun.tools.javac.util.Log
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaLogBase
import org.jetbrains.kotlin.kapt3.base.parseJavaFiles
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.test.KaptTestDirectives
import org.jetbrains.kotlin.kapt3.test.KaptTestDirectives.EXPECTED_ERROR
import org.jetbrains.kotlin.kapt3.test.handlers.ClassFileToSourceKaptStubHandler
import org.jetbrains.kotlin.kapt3.test.handlers.removeMetadataAnnotationContents
import org.jetbrains.kotlin.kapt3.test.messageCollectorProvider
import org.jetbrains.kotlin.kapt3.util.prettyPrint
import org.jetbrains.kotlin.test.Assertions
import org.jetbrains.kotlin.test.model.AnalysisHandler
import org.jetbrains.kotlin.test.model.TestArtifactKind
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.getRealJavaFiles
import org.jetbrains.kotlin.test.services.sourceFileProvider
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
import org.jetbrains.kotlin.test.utils.withExtension
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import java.io.File
import java.util.*
internal class Kapt4Handler(testServices: TestServices) : AnalysisHandler<Kapt4ContextBinaryArtifact>(
testServices,
failureDisablesNextSteps = true,
doNotRunIfThereWerePreviousFailures = true
) {
override val artifactKind: TestArtifactKind<Kapt4ContextBinaryArtifact>
get() = Kapt4ContextBinaryArtifact.Kind
override fun processModule(module: TestModule, info: Kapt4ContextBinaryArtifact) {
val validate = KaptTestDirectives.NO_VALIDATION !in module.directives
val (kaptContext) = info
val convertedFiles = getJavaFiles(info, module)
kaptContext.javaLog.interceptorData.files = convertedFiles.associateBy { it.sourceFile }
if (validate) kaptContext.compiler.enterTrees(convertedFiles)
val actualRaw = convertedFiles
.sortedBy { it.sourceFile.name }
.joinToString(ClassFileToSourceKaptStubHandler.FILE_SEPARATOR) { it.prettyPrint(kaptContext.context) }
val actual = StringUtil.convertLineSeparators(actualRaw.trim { it <= ' ' })
.trimTrailingWhitespacesAndAddNewlineAtEOF()
.let { removeMetadataAnnotationContents(it) }
assertions.assertAll(
{ assertions.checkTxt(module, actual) },
{
if (kaptContext.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
checkJavaCompilerErrors(module, kaptContext, actual)
}
}
)
}
private fun checkJavaCompilerErrors(
module: TestModule,
kaptContext: Kapt4ContextForStubGeneration,
actualDump: String
) {
val expectedErrors = (module.directives[EXPECTED_ERROR] + module.directives[Kapt4TestDirectives.EXPECTED_ERROR_K2]).sorted()
val log = Log.instance(kaptContext.context) as KaptJavaLogBase
val actualErrors = log.reportedDiagnostics
.filter { it.type == JCDiagnostic.DiagnosticType.ERROR }
.map {
// Unfortunately, we can't use the file name as it can contain temporary prefix
val name = it.source?.name?.substringAfterLast("/") ?: ""
val kind = when (name.substringAfterLast(".").lowercase()) {
"kt" -> "kotlin"
"java" -> "java"
else -> "other"
}
val javaLocation = "($kind:${it.lineNumber}:${it.columnNumber}) "
javaLocation + it.getMessage(Locale.US).lines().first()
}
.sorted()
log.flush()
val lineSeparator = System.getProperty("line.separator")
val actualErrorsStr = actualErrors.joinToString(lineSeparator) { it.toDirectiveView() }
if (expectedErrors.isEmpty()) {
assertions.fail { "There were errors during analysis:\n$actualErrorsStr\n\nStubs:\n\n$actualDump" }
} else {
val expectedErrorsStr = expectedErrors.joinToString(lineSeparator) { it.toDirectiveView() }
if (expectedErrorsStr != actualErrorsStr) {
assertions.assertEquals(expectedErrorsStr, actualErrorsStr) {
System.err.println(testServices.messageCollectorProvider.getErrorStream(module).toString("UTF8"))
"Expected error matching failed"
}
}
}
}
private fun getJavaFiles(
info: Kapt4ContextBinaryArtifact,
module: TestModule
): List<JCTree.JCCompilationUnit> {
val (kaptContext, kaptStubs) = info
val convertedFiles = kaptStubs.mapIndexed { index, stub ->
val sourceFile = createTempJavaFile("stub$index.java", stub.file.prettyPrint(kaptContext.context))
stub.writeMetadataIfNeeded(forSource = sourceFile)
sourceFile
}
val javaFiles = testServices.sourceFileProvider.getRealJavaFiles(module)
val allJavaFiles = javaFiles + convertedFiles
// A workaround needed for Javac to parse files correctly even if errors were already reported
// If nerrors > 0, "parseFiles()" returns the empty list
val oldErrorCount = kaptContext.compiler.log.nerrors
kaptContext.compiler.log.nerrors = 0
try {
val parsedJavaFiles = kaptContext.parseJavaFiles(allJavaFiles)
for (tree in parsedJavaFiles) {
val actualFile = File(tree.sourceFile.toUri())
// By default, JavaFileObject.getName() returns the absolute path to the file.
// In our test, such a path will be temporary, so the comparison against it will lead to flaky tests.
tree.sourcefile = KaptJavaFileObject(tree, tree.defs.firstIsInstance(), actualFile)
}
return parsedJavaFiles
} finally {
kaptContext.compiler.log.nerrors = oldErrorCount
}
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
private fun createTempJavaFile(name: String, text: String): File {
return testServices.sourceFileProvider.javaSourceDirectory.resolve(name).also {
it.writeText(text)
}
}
private fun String.toDirectiveView(): String = "// ${EXPECTED_ERROR.name}: $this"
}
fun Assertions.checkTxt(module: TestModule, actual: String) {
val testDataFile = module.files.first().originalFile
val firFile = testDataFile.withExtension("fir.txt")
val irFile = testDataFile.withExtension("ir.txt")
val txtFile = testDataFile.withExtension("txt")
val expectedFile = sequenceOf(firFile, irFile, txtFile)
.firstOrNull { it.exists() } ?: firFile
assertEqualsToFile(expectedFile, actual)
if (firFile.exists()) {
if (irFile.exists()) {
if (irFile.readText() == firFile.readText()) {
fail { ".fir.txt and .ir.txt golden files are identical. Remove $firFile." }
}
} else if (txtFile.exists() && txtFile.readText() == firFile.readText()) {
fail { ".fir.txt and .txt golden files are identical. Remove $firFile." }
}
}
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2023 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.kapt4
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
object Kapt4TestDirectives : SimpleDirectivesContainer() {
val EXPECTED_ERROR_K2 by stringDirective("Expected K2-specific error", multiLine = true)
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2023 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.kapt4
import org.jetbrains.kotlin.kapt4.Kapt4Directives.FIR_BLOCKED
import org.jetbrains.kotlin.test.WrappedException
import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.moduleStructure
internal class TemporaryKapt4Suppressor(testServices: TestServices) : AfterAnalysisChecker(testServices) {
override val directiveContainers: List<DirectivesContainer>
get() = listOf(Kapt4Directives)
override fun suppressIfNeeded(failedAssertions: List<WrappedException>): List<WrappedException> {
val hasFailures = failedAssertions.isNotEmpty()
if (suppressedByDirective(FIR_BLOCKED, hasFailures)) return emptyList()
return failedAssertions
}
private fun suppressedByDirective(directive: Directive, hasFailures: Boolean): Boolean {
val hasDirective = testServices.moduleStructure.modules.any { directive in it.directives }
if (hasDirective && !hasFailures) {
testServices.assertions.fail { "Test passes, remove $directive directive" }
}
return hasDirective
}
}
object Kapt4Directives : SimpleDirectivesContainer() {
val FIR_BLOCKED by stringDirective("Blocked by light classes")
}
@@ -0,0 +1,693 @@
/*
* Copyright 2010-2023 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.kapt4;
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 org.jetbrains.kotlin.generators.tests.GenerateTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter")
@TestDataPath("$PROJECT_ROOT")
public class KotlinKapt4ContextTestGenerated extends AbstractKotlinKapt4ContextTest {
@Test
@TestMetadata("abstractEnum.kt")
public void testAbstractEnum() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/abstractEnum.kt");
}
@Test
@TestMetadata("abstractMethods.kt")
public void testAbstractMethods() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/abstractMethods.kt");
}
@Test
@TestMetadata("aliasedImports.kt")
public void testAliasedImports() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/aliasedImports.kt");
}
@Test
public void testAllFilesPresentInConverter() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationWithFqNames.kt")
public void testAnnotationWithFqNames() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotationWithFqNames.kt");
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotations.kt");
}
@Test
@TestMetadata("annotations2.kt")
public void testAnnotations2() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotations2.kt");
}
@Test
@TestMetadata("annotations3.kt")
public void testAnnotations3() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotations3.kt");
}
@Test
@TestMetadata("annotationsWithConstants.kt")
public void testAnnotationsWithConstants() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt");
}
@Test
@TestMetadata("annotationsWithTargets.kt")
public void testAnnotationsWithTargets() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
}
@Test
@TestMetadata("anonymousDelegate.kt")
public void testAnonymousDelegate() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt");
}
@Test
@TestMetadata("anonymousInitializer.kt")
public void testAnonymousInitializer() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/anonymousInitializer.kt");
}
@Test
@TestMetadata("anonymousObjectInEnumSuperConstructor.kt")
public void testAnonymousObjectInEnumSuperConstructor() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/anonymousObjectInEnumSuperConstructor.kt");
}
@Test
@TestMetadata("comments.kt")
public void testComments() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/comments.kt");
}
@Test
@TestMetadata("commentsRemoved.kt")
public void testCommentsRemoved() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/commentsRemoved.kt");
}
@Test
@TestMetadata("cyrillicClassName.kt")
public void testCyrillicClassName() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/cyrillicClassName.kt");
}
@Test
@TestMetadata("dataClass.kt")
public void testDataClass() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/dataClass.kt");
}
@Test
@TestMetadata("defaultImpls.kt")
public void testDefaultImpls() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultImpls.kt");
}
@Test
@TestMetadata("defaultImplsWithTypeParameters.kt")
public void testDefaultImplsWithTypeParameters() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultImplsWithTypeParameters.kt");
}
@Test
@TestMetadata("defaultPackage.kt")
public void testDefaultPackage() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultPackage.kt");
}
@Test
@TestMetadata("defaultPackageCorrectErrorTypes.kt")
public void testDefaultPackageCorrectErrorTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultPackageCorrectErrorTypes.kt");
}
@Test
@TestMetadata("defaultParameterValueOff.kt")
public void testDefaultParameterValueOff() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultParameterValueOff.kt");
}
@Test
@TestMetadata("defaultParameterValueOn.kt")
public void testDefaultParameterValueOn() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/defaultParameterValueOn.kt");
}
@Test
@TestMetadata("delegateCorrectErrorTypes.kt")
public void testDelegateCorrectErrorTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/delegateCorrectErrorTypes.kt");
}
@Test
@TestMetadata("delegateToList.kt")
public void testDelegateToList() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/delegateToList.kt");
}
@Test
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/delegatedProperties.kt");
}
@Test
@TestMetadata("delegationAndCompanionObject.kt")
public void testDelegationAndCompanionObject() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/delegationAndCompanionObject.kt");
}
@Test
@TestMetadata("delegationToAnonymousObject.kt")
public void testDelegationToAnonymousObject() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/delegationToAnonymousObject.kt");
}
@Test
@TestMetadata("deprecated.kt")
public void testDeprecated() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/deprecated.kt");
}
@Test
@TestMetadata("enumImports.kt")
public void testEnumImports() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/enumImports.kt");
}
@Test
@TestMetadata("enumInCompanion.kt")
public void testEnumInCompanion() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/enumInCompanion.kt");
}
@Test
@TestMetadata("enumSecondaryConstructor.kt")
public void testEnumSecondaryConstructor() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/enumSecondaryConstructor.kt");
}
@Test
@TestMetadata("enums.kt")
public void testEnums() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/enums.kt");
}
@Test
@TestMetadata("errorExtensionReceiver.kt")
public void testErrorExtensionReceiver() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/errorExtensionReceiver.kt");
}
@Test
@TestMetadata("errorLocationMapping.kt")
public void testErrorLocationMapping() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/errorLocationMapping.kt");
}
@Test
@TestMetadata("errorSuperclass.kt")
public void testErrorSuperclass() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/errorSuperclass.kt");
}
@Test
@TestMetadata("errorSuperclassCorrectErrorTypes.kt")
public void testErrorSuperclassCorrectErrorTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/errorSuperclassCorrectErrorTypes.kt");
}
@Test
@TestMetadata("fileFacadeJvmName.kt")
public void testFileFacadeJvmName() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/fileFacadeJvmName.kt");
}
@Test
@TestMetadata("functions.kt")
public void testFunctions() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/functions.kt");
}
@Test
@TestMetadata("genericParameters.kt")
public void testGenericParameters() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/genericParameters.kt");
}
@Test
@TestMetadata("genericRawSignatures.kt")
public void testGenericRawSignatures() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/genericRawSignatures.kt");
}
@Test
@TestMetadata("genericSimple.kt")
public void testGenericSimple() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/genericSimple.kt");
}
@Test
@TestMetadata("ignoredMembers.kt")
public void testIgnoredMembers() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/ignoredMembers.kt");
}
@Test
@TestMetadata("implicitReturnTypes.kt")
public void testImplicitReturnTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/implicitReturnTypes.kt");
}
@Test
@TestMetadata("importsForErrorTypes.kt")
public void testImportsForErrorTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/importsForErrorTypes.kt");
}
@Test
@TestMetadata("importsKt22083.kt")
public void testImportsKt22083() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/importsKt22083.kt");
}
@Test
@TestMetadata("incorrectDelegate.kt")
public void testIncorrectDelegate() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/incorrectDelegate.kt");
}
@Test
@TestMetadata("inheritanceSimple.kt")
public void testInheritanceSimple() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt");
}
@Test
@TestMetadata("inlineClasses.kt")
public void testInlineClasses() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/inlineClasses.kt");
}
@Test
@TestMetadata("innerClassesWithTypeParameters.kt")
public void testInnerClassesWithTypeParameters() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/innerClassesWithTypeParameters.kt");
}
@Test
@TestMetadata("interfaceImplementation.kt")
public void testInterfaceImplementation() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/interfaceImplementation.kt");
}
@Test
@TestMetadata("invalidFieldName.kt")
public void testInvalidFieldName() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt");
}
@Test
@TestMetadata("javaKeywords.kt")
public void testJavaKeywords() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/javaKeywords.kt");
}
@Test
@TestMetadata("javaKeywordsInPackageNames.kt")
public void testJavaKeywordsInPackageNames() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/javaKeywordsInPackageNames.kt");
}
@Test
@TestMetadata("javadoc.kt")
public void testJavadoc() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/javadoc.kt");
}
@Test
@TestMetadata("jvmDefaultAll.kt")
public void testJvmDefaultAll() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmDefaultAll.kt");
}
@Test
@TestMetadata("jvmDefaultAllCompatibility.kt")
public void testJvmDefaultAllCompatibility() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmDefaultAllCompatibility.kt");
}
@Test
@TestMetadata("jvmOverloads.kt")
public void testJvmOverloads() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmOverloads.kt");
}
@Test
@TestMetadata("jvmRepeatableAnnotation.kt")
public void testJvmRepeatableAnnotation() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmRepeatableAnnotation.kt");
}
@Test
@TestMetadata("jvmStatic.kt")
public void testJvmStatic() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmStatic.kt");
}
@Test
@TestMetadata("jvmStaticFieldInParent.kt")
public void testJvmStaticFieldInParent() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/jvmStaticFieldInParent.kt");
}
@Test
@TestMetadata("kt14996.kt")
public void testKt14996() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt14996.kt");
}
@Test
@TestMetadata("kt14997.kt")
public void testKt14997() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt14997.kt");
}
@Test
@TestMetadata("kt14998.kt")
public void testKt14998() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt14998.kt");
}
@Test
@TestMetadata("kt15145.kt")
public void testKt15145() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt15145.kt");
}
@Test
@TestMetadata("kt17567.kt")
public void testKt17567() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt17567.kt");
}
@Test
@TestMetadata("kt18377.kt")
public void testKt18377() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt18377.kt");
}
@Test
@TestMetadata("kt18682.kt")
public void testKt18682() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt18682.kt");
}
@Test
@TestMetadata("kt19700.kt")
public void testKt19700() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt19700.kt");
}
@Test
@TestMetadata("kt19750.kt")
public void testKt19750() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt19750.kt");
}
@Test
@TestMetadata("kt24272.kt")
public void testKt24272() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt24272.kt");
}
@Test
@TestMetadata("kt25071.kt")
public void testKt25071() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt25071.kt");
}
@Test
@TestMetadata("kt27126.kt")
public void testKt27126() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt27126.kt");
}
@Test
@TestMetadata("kt28306.kt")
public void testKt28306() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt28306.kt");
}
@Test
@TestMetadata("kt32596.kt")
public void testKt32596() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt32596.kt");
}
@Test
@TestMetadata("kt34569.kt")
public void testKt34569() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt34569.kt");
}
@Test
@TestMetadata("kt43786.kt")
public void testKt43786() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/kt43786.kt");
}
@Test
@TestMetadata("lazyProperty.kt")
public void testLazyProperty() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/lazyProperty.kt");
}
@Test
@TestMetadata("leadingDollars.kt")
public void testLeadingDollars() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/leadingDollars.kt");
}
@Test
@TestMetadata("leadingDollars2.kt")
public void testLeadingDollars2() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/leadingDollars2.kt");
}
@Test
@TestMetadata("mapEntry.kt")
public void testMapEntry() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/mapEntry.kt");
}
@Test
@TestMetadata("maxErrorCount.kt")
public void testMaxErrorCount() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/maxErrorCount.kt");
}
@Test
@TestMetadata("methodParameterNames.kt")
public void testMethodParameterNames() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/methodParameterNames.kt");
}
@Test
@TestMetadata("methodPropertySignatureClash.kt")
public void testMethodPropertySignatureClash() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/methodPropertySignatureClash.kt");
}
@Test
@TestMetadata("modifiers.kt")
public void testModifiers() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/modifiers.kt");
}
@Test
@TestMetadata("multifileClass.kt")
public void testMultifileClass() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/multifileClass.kt");
}
@Test
@TestMetadata("multifileClassDefaultPackage.kt")
public void testMultifileClassDefaultPackage() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/multifileClassDefaultPackage.kt");
}
@Test
@TestMetadata("nestedClasses.kt")
public void testNestedClasses() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nestedClasses.kt");
}
@Test
@TestMetadata("nestedClasses2.kt")
public void testNestedClasses2() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt");
}
@Test
@TestMetadata("nestedClassesNonRootPackage.kt")
public void testNestedClassesNonRootPackage() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt");
}
@Test
@TestMetadata("nonExistentClass.kt")
public void testNonExistentClass() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nonExistentClass.kt");
}
@Test
@TestMetadata("nonExistentClassTypesConversion.kt")
public void testNonExistentClassTypesConversion() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nonExistentClassTypesConversion.kt");
}
@Test
@TestMetadata("nonExistentClassWIthoutCorrection.kt")
public void testNonExistentClassWIthoutCorrection() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/nonExistentClassWIthoutCorrection.kt");
}
@Test
@TestMetadata("primitiveTypes.kt")
public void testPrimitiveTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/primitiveTypes.kt");
}
@Test
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/properties.kt");
}
@Test
@TestMetadata("propertyAnnotations.kt")
public void testPropertyAnnotations() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/propertyAnnotations.kt");
}
@Test
@TestMetadata("recentlyNullable.kt")
public void testRecentlyNullable() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/recentlyNullable.kt");
}
@Test
@TestMetadata("repeatableAnnotations.kt")
public void testRepeatableAnnotations() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/repeatableAnnotations.kt");
}
@Test
@TestMetadata("secondaryConstructor.kt")
public void testSecondaryConstructor() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/secondaryConstructor.kt");
}
@Test
@TestMetadata("severalPackageParts.kt")
public void testSeveralPackageParts() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/severalPackageParts.kt");
}
@Test
@TestMetadata("starImports.kt")
public void testStarImports() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/starImports.kt");
}
@Test
@TestMetadata("strangeIdentifiers.kt")
public void testStrangeIdentifiers() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt");
}
@Test
@TestMetadata("strangeNames.kt")
public void testStrangeNames() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/strangeNames.kt");
}
@Test
@TestMetadata("stripMetadata.kt")
public void testStripMetadata() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/stripMetadata.kt");
}
@Test
@TestMetadata("superConstructorCall.kt")
public void testSuperConstructorCall() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/superConstructorCall.kt");
}
@Test
@TestMetadata("suspendArgName.kt")
public void testSuspendArgName() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/suspendArgName.kt");
}
@Test
@TestMetadata("suspendErrorTypes.kt")
public void testSuspendErrorTypes() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/suspendErrorTypes.kt");
}
@Test
@TestMetadata("suspendFunctionSupertype.kt")
public void testSuspendFunctionSupertype() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/suspendFunctionSupertype.kt");
}
@Test
@TestMetadata("suspendFunctionWithBigArity.kt")
public void testSuspendFunctionWithBigArity() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt");
}
@Test
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/topLevel.kt");
}
@Test
@TestMetadata("unresolvedDelegateExpression.kt")
public void testUnresolvedDelegateExpression() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/unresolvedDelegateExpression.kt");
}
@Test
@TestMetadata("unsafePropertyInitializers.kt")
public void testUnsafePropertyInitializers() throws Exception {
runTest("plugins/kapt4/../kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt");
}
}