Skip to content

Commit d050c49

Browse files
committed
add annotation validation to validate API
1 parent 12e3cbe commit d050c49

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
@@ -2,77 +2,69 @@ package com.google.devtools.ksp.visitor
22

33
import com.google.devtools.ksp.symbol.*
44

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

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

14-
private fun validateType(type: KSType): Boolean {
15-
return !type.isError && !type.arguments.any { it.type?.accept(this, Unit) == false }
14+
override fun visitDeclaration(declaration: KSDeclaration, data: KSNode?): Boolean {
15+
if (!predicate(data, declaration)) {
16+
return true
17+
}
18+
if (!declaration.typeParameters.any { it.accept(this, declaration) }) {
19+
return false
20+
}
21+
return super.visitDeclaration(declaration, data)
1622
}
1723

18-
override fun defaultHandler(node: KSNode, data: Unit): Boolean {
19-
throw IllegalStateException("unhandled validation condition, please file a bug at https://github.com/google/ksp/issues/new")
24+
override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: KSNode?): Boolean {
25+
return !predicate(data, declarationContainer) || declarationContainer.declarations.all { it.accept(this, declarationContainer) }
2026
}
2127

22-
override fun visitTypeReference(typeReference: KSTypeReference, data: Unit): Boolean {
28+
override fun visitTypeParameter(typeParameter: KSTypeParameter, data: KSNode?): Boolean {
29+
return !predicate(data, typeParameter) || typeParameter.bounds.all{ it.accept(this, typeParameter) }
30+
}
31+
32+
override fun visitAnnotation(annotation: KSAnnotation, data: KSNode?): Boolean {
33+
return !predicate(data, annotation) || annotation.annotationType.accept(this, annotation)
34+
}
35+
36+
override fun visitTypeReference(typeReference: KSTypeReference, data: KSNode?): Boolean {
2337
return validateType(typeReference.resolve())
2438
}
2539

26-
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit): Boolean {
27-
if (!validateTypeParameters(classDeclaration)) {
28-
return false
29-
}
40+
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: KSNode?): Boolean {
3041
if (classDeclaration.asStarProjectedType().isError) {
3142
return false
3243
}
33-
if (classDeclaration.superTypes.any { predicate(classDeclaration, it) && !it.accept(this, Unit) }) {
44+
if (!classDeclaration.superTypes.all{ it.accept(this, classDeclaration) }) {
3445
return false
3546
}
36-
if (!validateDeclarations(classDeclaration)) {
37-
return false
38-
}
39-
return true
47+
return super.visitClassDeclaration(classDeclaration, data)
4048
}
4149

42-
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit): Boolean {
50+
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: KSNode?): Boolean {
4351
if (function.returnType != null && !(predicate(function, function.returnType!!) && function.returnType!!.accept(this, data))) {
4452
return false
4553
}
46-
if (function.parameters.any { predicate(function, it) && !it.accept(this, Unit)}) {
47-
return false
48-
}
49-
if (!validateTypeParameters(function)) {
50-
return false
51-
}
52-
if (!validateDeclarations(function)) {
54+
if (!function.parameters.all{ it.accept(this, function) }) {
5355
return false
5456
}
55-
return true
57+
return super.visitFunctionDeclaration(function, data)
5658
}
5759

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

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

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)