|
| 1 | +import com.google.devtools.ksp.processing.CodeGenerator |
| 2 | +import com.google.devtools.ksp.processing.Dependencies |
| 3 | +import com.google.devtools.ksp.processing.KSPLogger |
| 4 | +import com.google.devtools.ksp.processing.Resolver |
| 5 | +import com.google.devtools.ksp.processing.SymbolProcessor |
| 6 | +import com.google.devtools.ksp.symbol.* |
| 7 | +import java.io.File |
| 8 | +import java.io.OutputStream |
| 9 | + |
| 10 | + |
| 11 | +class TestProcessor : SymbolProcessor { |
| 12 | + lateinit var codeGenerator: CodeGenerator |
| 13 | + lateinit var file: OutputStream |
| 14 | + |
| 15 | + fun emit(s: String, indent: String) { |
| 16 | + file.appendText("$indent$s\n") |
| 17 | + } |
| 18 | + |
| 19 | + override fun finish() { |
| 20 | + emit("TestProcessor: finish()", "") |
| 21 | + file.close() |
| 22 | + } |
| 23 | + |
| 24 | + override fun init(options: Map<String, String>, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator, logger: KSPLogger) { |
| 25 | + this.codeGenerator = codeGenerator |
| 26 | + file = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log") |
| 27 | + emit("TestProcessor: init($options)", "") |
| 28 | + |
| 29 | + val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "Generated", "java") |
| 30 | + javaFile.appendText("class Generated {}") |
| 31 | + } |
| 32 | + |
| 33 | + override fun process(resolver: Resolver) { |
| 34 | + val fileKt = codeGenerator.createNewFile(Dependencies(false), "", "HELLO", "java") |
| 35 | + fileKt.appendText("public class HELLO{\n") |
| 36 | + fileKt.appendText("public int foo() { return 1234; }\n") |
| 37 | + fileKt.appendText("}") |
| 38 | + |
| 39 | + val files = resolver.getAllFiles() |
| 40 | + emit("TestProcessor: process()", "") |
| 41 | + val visitor = TestVisitor() |
| 42 | + for (file in files) { |
| 43 | + emit("TestProcessor: processing ${file.fileName}", "") |
| 44 | + file.accept(visitor, "") |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + inner class TestVisitor : KSVisitor<String, Unit> { |
| 49 | + |
| 50 | + override fun visitReferenceElement(element: KSReferenceElement, data: String) { |
| 51 | + } |
| 52 | + |
| 53 | + override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: String) { |
| 54 | + TODO("Not yet implemented") |
| 55 | + } |
| 56 | + |
| 57 | + override fun visitNode(node: KSNode, data: String) { |
| 58 | + TODO("Not yet implemented") |
| 59 | + } |
| 60 | + |
| 61 | + override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: String) { |
| 62 | + TODO("Not yet implemented") |
| 63 | + } |
| 64 | + |
| 65 | + override fun visitDynamicReference(reference: KSDynamicReference, data: String) { |
| 66 | + TODO("Not yet implemented") |
| 67 | + } |
| 68 | + val visited = HashSet<Any>() |
| 69 | + |
| 70 | + private fun checkVisited(symbol: Any): Boolean { |
| 71 | + return if (visited.contains(symbol)) { |
| 72 | + true |
| 73 | + } else { |
| 74 | + visited.add(symbol) |
| 75 | + false |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + private fun invokeCommonDeclarationApis(declaration: KSDeclaration, indent: String) { |
| 80 | + emit( |
| 81 | + "${declaration.modifiers.joinToString(" ")} ${declaration.simpleName.asString()}", indent |
| 82 | + ) |
| 83 | + declaration.annotations.map { it.accept(this, "$indent ") } |
| 84 | + if (declaration.parentDeclaration != null) |
| 85 | + emit(" enclosing: ${declaration.parentDeclaration!!.qualifiedName?.asString()}", indent) |
| 86 | + declaration.containingFile?.let { emit("${it.packageName.asString()}.${it.fileName}", indent) } |
| 87 | + declaration.typeParameters.map { it.accept(this, "$indent ") } |
| 88 | + } |
| 89 | + |
| 90 | + override fun visitFile(file: KSFile, data: String) { |
| 91 | +// if (!file.packageName.asString().startsWith("eu.kanade.tachiyomi.data")) { |
| 92 | +// return |
| 93 | +// } |
| 94 | + if (checkVisited(file)) return |
| 95 | + file.annotations.map{ it.accept(this, "$data ") } |
| 96 | + emit(file.packageName.asString(), data) |
| 97 | + for (declaration in file.declarations) { |
| 98 | + declaration.accept(this, data) |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + override fun visitAnnotation(annotation: KSAnnotation, data: String) { |
| 103 | + if (checkVisited(annotation)) return |
| 104 | + emit("annotation", data) |
| 105 | + annotation.annotationType.accept(this, "$data ") |
| 106 | + annotation.arguments.map { it.accept(this, "$data ") } |
| 107 | + } |
| 108 | + |
| 109 | + override fun visitCallableReference(reference: KSCallableReference, data: String) { |
| 110 | + if (checkVisited(reference)) return |
| 111 | + emit("element: ", data) |
| 112 | + reference.functionParameters.map { it.accept(this, "$data ") } |
| 113 | + reference.receiverType?.accept(this, "$data receiver") |
| 114 | + reference.returnType.accept(this, "$data ") |
| 115 | + } |
| 116 | + |
| 117 | + override fun visitPropertyGetter(getter: KSPropertyGetter, data: String) { |
| 118 | + if (checkVisited(getter)) return |
| 119 | + emit("propertyGetter: ", data) |
| 120 | + getter.annotations.map { it.accept(this, "$data ") } |
| 121 | + emit(getter.modifiers.joinToString(" "), data) |
| 122 | + getter.returnType?.accept(this, "$data ") |
| 123 | + } |
| 124 | + |
| 125 | + override fun visitPropertySetter(setter: KSPropertySetter, data: String) { |
| 126 | + if (checkVisited(setter)) return |
| 127 | + emit("propertySetter: ", data) |
| 128 | + setter.annotations.map { it.accept(this, "$data ") } |
| 129 | + emit(setter.modifiers.joinToString(" "), data) |
| 130 | +// setter.parameter.accept(this, "$data ") |
| 131 | + } |
| 132 | + |
| 133 | + override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) { |
| 134 | + if (checkVisited(typeArgument)) return |
| 135 | + typeArgument.annotations.map{ it.accept(this, "$data ") } |
| 136 | + emit( |
| 137 | + when (typeArgument.variance) { |
| 138 | + Variance.STAR -> "*" |
| 139 | + Variance.COVARIANT -> "out" |
| 140 | + Variance.CONTRAVARIANT -> "in" |
| 141 | + else -> "" |
| 142 | + }, data |
| 143 | + ) |
| 144 | + typeArgument.type?.accept(this, "$data ") |
| 145 | + } |
| 146 | + |
| 147 | + override fun visitTypeParameter(typeParameter: KSTypeParameter, data: String) { |
| 148 | + if (checkVisited(typeParameter)) return |
| 149 | + typeParameter.annotations.map{ it.accept(this, "$data ") } |
| 150 | + if (typeParameter.isReified) { |
| 151 | + emit("reified ", data) |
| 152 | + } |
| 153 | + emit( |
| 154 | + when (typeParameter.variance) { |
| 155 | + Variance.COVARIANT -> "out " |
| 156 | + Variance.CONTRAVARIANT -> "in " |
| 157 | + else -> "" |
| 158 | + } + typeParameter.name.asString(), data |
| 159 | + ) |
| 160 | + if (typeParameter.bounds.isNotEmpty()) { |
| 161 | + typeParameter.bounds.map { it.accept(this, "$data ") } |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + override fun visitValueParameter(valueParameter: KSValueParameter, data: String) { |
| 166 | + if (checkVisited(valueParameter)) return |
| 167 | + valueParameter.annotations.map { it.accept(this, "$data ") } |
| 168 | + if (valueParameter.isVararg) { |
| 169 | + emit("vararg", "$data ") |
| 170 | + } |
| 171 | + if (valueParameter.isNoInline) { |
| 172 | + emit("noinline", "$data ") |
| 173 | + } |
| 174 | + if (valueParameter.isCrossInline) { |
| 175 | + emit("crossinline ", "$data ") |
| 176 | + } |
| 177 | + emit(valueParameter.name?.asString() ?: "_", "$data ") |
| 178 | + valueParameter.type.accept(this, "$data ") |
| 179 | + } |
| 180 | + |
| 181 | + override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: String) { |
| 182 | + if (checkVisited(function)) return |
| 183 | + invokeCommonDeclarationApis(function, data) |
| 184 | + for (declaration in function.declarations) { |
| 185 | + declaration.accept(this, "$data ") |
| 186 | + } |
| 187 | + function.parameters.map { it.accept(this, "$data ") } |
| 188 | + function.typeParameters.map { it.accept(this, "$data ") } |
| 189 | + function.extensionReceiver?.accept(this, "$data extension:") |
| 190 | + emit("returnType:", data) |
| 191 | + function.returnType?.accept(this, "$data ") |
| 192 | + } |
| 193 | + |
| 194 | + override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: String) { |
| 195 | + if (checkVisited(classDeclaration)) return |
| 196 | + invokeCommonDeclarationApis(classDeclaration, data) |
| 197 | + emit(classDeclaration.classKind.type, data) |
| 198 | + for (declaration in classDeclaration.declarations) { |
| 199 | + declaration.accept(this, "$data ") |
| 200 | + } |
| 201 | + classDeclaration.superTypes.map { it.accept(this, "$data ") } |
| 202 | + classDeclaration.primaryConstructor?.accept(this, "$data ") |
| 203 | + } |
| 204 | + |
| 205 | + override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: String) { |
| 206 | + if (checkVisited(property)) return |
| 207 | + invokeCommonDeclarationApis(property, data) |
| 208 | + property.type.accept(this, "$data ") |
| 209 | + property.extensionReceiver?.accept(this, "$data extension:") |
| 210 | + property.setter?.accept(this, "$data ") |
| 211 | + property.getter?.accept(this, "$data ") |
| 212 | + } |
| 213 | + |
| 214 | + override fun visitTypeReference(typeReference: KSTypeReference, data: String) { |
| 215 | + if (checkVisited(typeReference)) return |
| 216 | + typeReference.annotations.map{ it.accept(this, "$data ") } |
| 217 | + val type = typeReference.resolve() |
| 218 | + type.let { |
| 219 | + emit("resolved to: ${it.declaration.qualifiedName?.asString()}", data) |
| 220 | + } |
| 221 | + //resolved.accept(this, "$data ") |
| 222 | + // TODO: KSTypeReferenceJavaImpl hasn't completed yet. |
| 223 | + try { |
| 224 | + typeReference.element?.accept(this, "$data ") |
| 225 | + } catch (e: IllegalStateException) { |
| 226 | + emit("TestProcessor: exception: $e", data) |
| 227 | + } |
| 228 | + } |
| 229 | + |
| 230 | + override fun visitAnnotated(annotated: KSAnnotated, data: String) { |
| 231 | + } |
| 232 | + |
| 233 | + override fun visitDeclaration(declaration: KSDeclaration, data: String) { |
| 234 | + } |
| 235 | + |
| 236 | + override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: String) { |
| 237 | + } |
| 238 | + |
| 239 | + override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: String) { |
| 240 | + } |
| 241 | + |
| 242 | + override fun visitClassifierReference(reference: KSClassifierReference, data: String) { |
| 243 | + if (checkVisited(reference)) return |
| 244 | + if (reference.typeArguments.isNotEmpty()) { |
| 245 | + reference.typeArguments.map { it.accept(this, "$data ") } |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + override fun visitTypeAlias(typeAlias: KSTypeAlias, data: String) { |
| 250 | + } |
| 251 | + |
| 252 | + override fun visitValueArgument(valueArgument: KSValueArgument, data: String) { |
| 253 | + if (checkVisited(valueArgument)) return |
| 254 | + val name = valueArgument.name?.asString() ?: "<no name>" |
| 255 | + emit("$name: ${valueArgument.value}", data) |
| 256 | + valueArgument.annotations.map { it.accept(this, "$data ") } |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | +} |
| 261 | + |
| 262 | + |
0 commit comments