1919
2020package deezer.kustomexport.compiler.js.pattern
2121
22+ import com.google.devtools.ksp.containingFile
23+ import com.google.devtools.ksp.getAllSuperTypes
2224import com.google.devtools.ksp.getConstructors
2325import com.google.devtools.ksp.getDeclaredFunctions
2426import com.google.devtools.ksp.getDeclaredProperties
@@ -28,8 +30,11 @@ import com.google.devtools.ksp.symbol.ClassKind
2830import com.google.devtools.ksp.symbol.KSClassDeclaration
2931import com.google.devtools.ksp.symbol.KSFunctionDeclaration
3032import com.google.devtools.ksp.symbol.KSName
33+ import com.google.devtools.ksp.symbol.KSNode
3134import com.google.devtools.ksp.symbol.KSTypeParameter
35+ import com.google.devtools.ksp.symbol.KSTypeReference
3236import com.google.devtools.ksp.symbol.Modifier
37+ import com.squareup.kotlinpoet.THROWABLE
3338import com.squareup.kotlinpoet.TypeName
3439import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
3540import com.squareup.kotlinpoet.ksp.TypeParameterResolver
@@ -70,12 +75,7 @@ fun parseClass(
7075 forcedConcreteTypeParameters : List <Pair <String , TypeName >>? = null,
7176 exportedClassSimpleName : String
7277): Descriptor {
73- if (classDeclaration.isThrowable()) {
74- error(
75- " Cannot parse a class that is Throwable: " +
76- (classDeclaration.qualifiedName?.asString() ? : classDeclaration.simpleName.asString())
77- )
78- }
78+ classDeclaration.assertNotThrowable(classDeclaration)
7979 val typeParamResolver = classDeclaration.typeParameters.toTypeParameterResolver()
8080
8181 val concreteTypeParameters: MutableList <TypeParameterDescriptor > =
@@ -87,11 +87,7 @@ fun parseClass(
8787 val superTypes = classDeclaration.superTypes
8888 .map { superType ->
8989 val superTypeName = superType.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters)
90-
9190 val declaration = superType.resolve().declaration
92- // val qualifiedName = (declaration as? KSClassDeclaration)?.qualifiedName
93- // val isKotlinException = ALL_KOTLIN_EXCEPTIONS.any { it.canonicalName == qualifiedName }
94-
9591 if (declaration is KSClassDeclaration ) {
9692 val ctors = declaration.getConstructors().toList()
9793 val superParams = if (ctors.isNotEmpty()) emptyList<ParameterDescriptor >() else null
@@ -104,6 +100,7 @@ fun parseClass(
104100 .toList()
105101
106102 val constructorParams = classDeclaration.primaryConstructor?.parameters?.map {
103+ it.type.assertNotThrowable(it)
107104 ParameterDescriptor (
108105 name = it.name!! .asString(),
109106 type = it.type.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters)
@@ -192,8 +189,8 @@ private fun buildConcreteTypeParameters(
192189 type.asClassName()
193190 } catch (t: Throwable ) {
194191 Logger .error(
195- " Cannot use @KustomException on a not concrete generics class." ,
196- firstTypeParameterProvider()
192+ message = " Cannot use @KustomExport on a not concrete generics class." ,
193+ symbol = firstTypeParameterProvider()
197194 )
198195 error(t)
199196 }
@@ -214,16 +211,6 @@ private val nonExportableFunctions = listOf(
214211 " toString" ,
215212 " copy" ,
216213
217- // For exceptions :
218- " getLocalizedMessage" ,
219- " initCause" ,
220- " printStackTrace" ,
221- " fillInStackTrace" ,
222- " getStackTrace" ,
223- " setStackTrace" ,
224- " addSuppressed" ,
225- " getSuppressed" ,
226-
227214 ) + (1 .. 30 ).map { " component$it " }
228215
229216@OptIn(KotlinPoetKspPreview ::class )
@@ -244,19 +231,22 @@ private fun KSFunctionDeclaration.toDescriptor(
244231 declaredNames : Sequence <KSName >,
245232 typeParamResolver : TypeParameterResolver ,
246233 concreteTypeParameters : MutableList <TypeParameterDescriptor >
247- ) =
248- FunctionDescriptor (
234+ ): FunctionDescriptor {
235+ returnType?.assertNotThrowable(this )
236+ return FunctionDescriptor (
249237 name = simpleName.asString(),
250238 isOverride = findOverridee() != null || ! declaredNames.contains(simpleName),
251239 isSuspend = modifiers.contains(Modifier .SUSPEND ),
252240 returnType = returnType!! .toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
253241 parameters = parameters.map { p ->
242+ p.type.assertNotThrowable(p)
254243 ParameterDescriptor (
255244 name = p.name?.asString() ? : TODO (" not sure what we want here" ),
256245 type = p.type.toTypeNamePatch(typeParamResolver).cached(concreteTypeParameters),
257246 )
258247 }
259248 )
249+ }
260250
261251@OptIn(KotlinPoetKspPreview ::class )
262252fun KSClassDeclaration.parseProperties (
@@ -266,10 +256,11 @@ fun KSClassDeclaration.parseProperties(
266256 val declaredNames = getDeclaredProperties().mapNotNull { it.simpleName }
267257 return getAllProperties().mapNotNull { prop ->
268258 // TODO: rework configuration by naming
269- val classExtendsException = this .simpleName.asString().endsWith(" Exception" )
270259 if (prop.isPrivate()) {
271260 null // Cannot be accessed
272261 } else {
262+ prop.type.assertNotThrowable(prop)
263+
273264 val type = prop.type.toTypeNamePatch(typeParamResolver)
274265 // Retrieve the names of function arguments, like: (*MyName*: String) -> Unit
275266 // Problem: we use KotlinPoet TypeName for the mapping, and it doesn't have the value available.
@@ -279,7 +270,6 @@ fun KSClassDeclaration.parseProperties(
279270 }
280271 } else emptyList()
281272 */
282-
283273 PropertyDescriptor (
284274 name = prop.simpleName.asString(),
285275 type = type.cached(concreteTypeParameters),
@@ -291,21 +281,42 @@ fun KSClassDeclaration.parseProperties(
291281 }.toList()
292282}
293283
284+ fun KSTypeReference.assertNotThrowable (symbol : KSNode ) {
285+ val decl = resolve().declaration
286+ if (decl is KSClassDeclaration ) {
287+ decl.assertNotThrowable(symbol)
288+ }
289+ }
290+
291+ fun KSClassDeclaration.assertNotThrowable (symbol : KSNode ) {
292+ if (isThrowable() && qualifiedName?.asString() != THROWABLE .canonicalName) {
293+ Logger .error(
294+ message = " Cannot export ${this .qualifiedName?.asString() ? : simpleName.asString()} .\n " +
295+ " You cannot export an Exception or subclasses of Exception but you can export a Throwable instead." ,
296+ symbol = symbol
297+ )
298+ }
299+ }
300+
294301fun KSClassDeclaration.isThrowable (): Boolean {
295- superTypes
302+ if (toClassName() in ALL_KOTLIN_EXCEPTIONS ) {
303+ return true
304+ }
305+
306+ getAllSuperTypes()
296307 .forEach { superType ->
297- val superTypeResolved = superType.resolve()
298- if (superTypeResolved.toClassName() in ALL_KOTLIN_EXCEPTIONS ) {
308+ if (superType.toClassName() in ALL_KOTLIN_EXCEPTIONS ) {
299309 return true
300310 }
301311
302- val declaration = superTypeResolved .declaration
312+ val declaration = superType .declaration
303313 if (declaration is KSClassDeclaration && declaration.isThrowable()) {
304314 return true
305315 }
306316 }
307317 return false
308318}
309319
310- fun TypeName.cached (concreteTypeParameters : List <TypeParameterDescriptor >) =
311- OriginTypeName (this , concreteTypeParameters)
320+ fun TypeName.cached (concreteTypeParameters : List <TypeParameterDescriptor >): OriginTypeName {
321+ return OriginTypeName (this , concreteTypeParameters)
322+ }
0 commit comments