Skip to content

Commit ff99438

Browse files
committed
add annotation validation to validate API
1 parent 17778fc commit ff99438

File tree

4 files changed

+47
-44
lines changed

4 files changed

+47
-44
lines changed

api/src/main/kotlin/com/google/devtools/ksp/utils.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ fun KSDeclaration.isLocal(): Boolean {
8383
* Perform a validation on a given symbol to check if all interested types in symbols enclosed scope are valid, i.e. resolvable.
8484
* @param predicate: A lambda for filtering interested symbols for performance purpose. Default checks all.
8585
*/
86-
fun KSNode.validate(predicate: (KSNode, KSNode) -> Boolean = { _, _-> true } ): Boolean {
87-
return this.accept(KSValidateVisitor(predicate), Unit)
86+
fun KSNode.validate(predicate: (KSNode?, KSNode) -> Boolean = { _, _-> true } ): Boolean {
87+
return this.accept(KSValidateVisitor(predicate), null)
8888
}
8989

9090
/**

api/src/main/kotlin/com/google/devtools/ksp/visitor/KSValidateVisitor.kt

+34-42
Original file line numberDiff line numberDiff line change
@@ -3,77 +3,69 @@ package com.google.devtools.ksp.visitor
33
import com.google.devtools.ksp.ExceptionMessage
44
import com.google.devtools.ksp.symbol.*
55

6-
class KSValidateVisitor(private val predicate: (KSNode, KSNode) -> Boolean) : KSDefaultVisitor<Unit, Boolean>() {
7-
private fun validateDeclarations(declarationContainer: KSDeclarationContainer): Boolean {
8-
return !declarationContainer.declarations.any { predicate(declarationContainer, it) && !it.accept(this, Unit) }
6+
class KSValidateVisitor(private val predicate: (KSNode?, KSNode) -> Boolean) : KSDefaultVisitor<KSNode?, Boolean>() {
7+
private fun validateType(type: KSType): Boolean {
8+
return !type.isError && !type.arguments.any { it.type?.accept(this, null) == false }
99
}
1010

11-
private fun validateTypeParameters(declaration: KSDeclaration): Boolean {
12-
return !declaration.typeParameters.any { predicate(declaration, it) && !it.accept(this, Unit) }
11+
override fun defaultHandler(node: KSNode, data: KSNode?): Boolean {
12+
throw IllegalStateException("unhandled validation condition, please file a bug at https://github.com/google/ksp/issues/new")
1313
}
1414

15-
private fun validateType(type: KSType): Boolean {
16-
return !type.isError && !type.arguments.any { it.type?.accept(this, Unit) == false }
15+
override fun visitDeclaration(declaration: KSDeclaration, data: KSNode?): Boolean {
16+
if (!predicate(data, declaration)) {
17+
return true
18+
}
19+
if (!declaration.typeParameters.any { it.accept(this, declaration) }) {
20+
return false
21+
}
22+
return super.visitDeclaration(declaration, data)
23+
}
24+
25+
override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: KSNode?): Boolean {
26+
return !predicate(data, declarationContainer) || declarationContainer.declarations.all { it.accept(this, declarationContainer) }
27+
}
28+
29+
override fun visitTypeParameter(typeParameter: KSTypeParameter, data: KSNode?): Boolean {
30+
return !predicate(data, typeParameter) || typeParameter.bounds.all{ it.accept(this, typeParameter) }
1731
}
1832

19-
override fun defaultHandler(node: KSNode, data: Unit): Boolean {
20-
throw IllegalStateException("unhandled validation condition, $ExceptionMessage")
33+
override fun visitAnnotation(annotation: KSAnnotation, data: KSNode?): Boolean {
34+
return !predicate(data, annotation) || annotation.annotationType.accept(this, annotation)
2135
}
2236

23-
override fun visitTypeReference(typeReference: KSTypeReference, data: Unit): Boolean {
37+
override fun visitTypeReference(typeReference: KSTypeReference, data: KSNode?): Boolean {
2438
return validateType(typeReference.resolve())
2539
}
2640

27-
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit): Boolean {
28-
if (!validateTypeParameters(classDeclaration)) {
29-
return false
30-
}
41+
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: KSNode?): Boolean {
3142
if (classDeclaration.asStarProjectedType().isError) {
3243
return false
3344
}
34-
if (classDeclaration.superTypes.any { predicate(classDeclaration, it) && !it.accept(this, Unit) }) {
45+
if (!classDeclaration.superTypes.all{ it.accept(this, classDeclaration) }) {
3546
return false
3647
}
37-
if (!validateDeclarations(classDeclaration)) {
38-
return false
39-
}
40-
return true
48+
return super.visitClassDeclaration(classDeclaration, data)
4149
}
4250

43-
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit): Boolean {
51+
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: KSNode?): Boolean {
4452
if (function.returnType != null && !(predicate(function, function.returnType!!) && function.returnType!!.accept(this, data))) {
4553
return false
4654
}
47-
if (function.parameters.any { predicate(function, it) && !it.accept(this, Unit)}) {
48-
return false
49-
}
50-
if (!validateTypeParameters(function)) {
55+
if (!function.parameters.all{ it.accept(this, function) }) {
5156
return false
5257
}
53-
if (!validateDeclarations(function)) {
54-
return false
55-
}
56-
return true
58+
return super.visitFunctionDeclaration(function, data)
5759
}
5860

59-
override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit): Boolean {
61+
override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: KSNode?): Boolean {
6062
if (predicate(property, property.type) && property.type.resolve().isError) {
6163
return false
6264
}
63-
if (!validateTypeParameters(property)) {
64-
return false
65-
}
66-
return true
67-
}
68-
69-
override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit): Boolean {
70-
if (typeParameter.bounds.any { predicate(typeParameter, it) && !it.accept(this, Unit) }) {
71-
return false
72-
}
73-
return true
65+
return super.visitPropertyDeclaration(property, data)
7466
}
7567

76-
override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit): Boolean {
77-
return valueParameter.type?.accept(this, Unit) != false
68+
override fun visitValueParameter(valueParameter: KSValueParameter, data: KSNode?): Boolean {
69+
return valueParameter.type.accept(this, valueParameter)
7870
}
7971
}

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt

+2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ class ValidateProcessor : AbstractTestProcessor() {
2222
val GoodClass = resolver.getClassDeclarationByName("GoodClass")!!
2323
val C = resolver.getClassDeclarationByName("C")!!
2424
val BadJavaClass = resolver.getClassDeclarationByName("BadJavaClass")!!
25+
val ErrorAnnotationType = resolver.getClassDeclarationByName("ErrorAnnotationType")!!
2526
validate(ErrorInMember)
2627
ErrorInMember.declarations.map { validate(it) }
2728
validate(GoodClass)
2829
validate(C)
2930
validate(BadJavaClass)
31+
validate(ErrorAnnotationType)
3032
}
3133
}

compiler-plugin/testData/api/validateTypes.kt

+9
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,24 @@
77
// GoodClass valid
88
// C valid
99
// BadJavaClass invalid
10+
// ErrorAnnotationType invalid
1011
// END
1112
// FILE: a.kt
13+
annotation class Anno(val i: Int)
14+
15+
@Anno(1)
1216
class ErrorInMember : C {
1317
val goodProp: Int
1418
fun errorFun(): NonExistType {
1519

1620
}
1721
}
1822

23+
@NonExistAnnotation
24+
class ErrorAnnotationType {
25+
}
26+
27+
@Anno(1)
1928
open class GoodClass {
2029
val a: Int
2130

0 commit comments

Comments
 (0)