1 /* 2 * Copyright 2022 Google LLC 3 * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 import com.google.devtools.ksp.isLocal 18 import com.google.devtools.ksp.processing.CodeGenerator 19 import com.google.devtools.ksp.processing.Resolver 20 import com.google.devtools.ksp.processing.SymbolProcessor 21 import com.google.devtools.ksp.processing.SymbolProcessorEnvironment 22 import com.google.devtools.ksp.processing.SymbolProcessorProvider 23 import com.google.devtools.ksp.symbol.* 24 import com.google.devtools.ksp.visitor.KSTopDownVisitor 25 import java.io.File 26 27 class ExhaustiveProcessor( 28 val codeGenerator: CodeGenerator, 29 val options: Map<String, String> 30 ) : SymbolProcessor { 31 val file: File? = null finishnull32 override fun finish() { 33 } 34 processnull35 override fun process(resolver: Resolver): List<KSAnnotated> { 36 file?.writeText("") 37 val visitor = ExhaustiveVisitor() 38 resolver.getAllFiles().forEach { it.accept(visitor, Unit) } 39 file?.appendText(visitor.collectedNodes.joinToString("\n")) 40 return emptyList() 41 } 42 43 inner class ExhaustiveVisitor : KSTopDownVisitor<Unit, Unit>() { 44 val collectedNodes = mutableListOf<String>() 45 defaultHandlernull46 override fun defaultHandler(node: KSNode, data: Unit) { 47 file?.appendText("--- visiting ${node.location} ---\n") 48 } 49 visitAnnotatednull50 override fun visitAnnotated(annotated: KSAnnotated, data: Unit) { 51 super.visitAnnotated(annotated, data) 52 } 53 visitAnnotationnull54 override fun visitAnnotation(annotation: KSAnnotation, data: Unit) { 55 file?.appendText("ANNO: ${annotation.shortName}") 56 annotation.shortName 57 annotation.useSiteTarget 58 super.visitAnnotation(annotation, data) 59 } 60 visitCallableReferencenull61 override fun visitCallableReference(reference: KSCallableReference, data: Unit) { 62 super.visitCallableReference(reference, data) 63 } 64 visitClassDeclarationnull65 override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { 66 classDeclaration.classKind 67 classDeclaration.primaryConstructor?.accept(this, Unit) 68 classDeclaration.isCompanionObject 69 classDeclaration.getAllFunctions().map { it.accept(this, Unit) } 70 classDeclaration.getAllProperties().map { it.accept(this, Unit) } 71 classDeclaration.asStarProjectedType() 72 if (classDeclaration.origin != Origin.KOTLIN_LIB && classDeclaration.origin != Origin.JAVA_LIB) { 73 classDeclaration.superTypes.map { it.accept(this, Unit) } 74 } 75 return super.visitClassDeclaration(classDeclaration, data) 76 } 77 visitClassifierReferencenull78 override fun visitClassifierReference(reference: KSClassifierReference, data: Unit) { 79 reference.referencedName() 80 super.visitClassifierReference(reference, data) 81 } 82 visitDeclarationnull83 override fun visitDeclaration(declaration: KSDeclaration, data: Unit) { 84 declaration.containingFile 85 declaration.packageName 86 declaration.qualifiedName 87 declaration.simpleName 88 declaration.parentDeclaration 89 super.visitDeclaration(declaration, data) 90 } 91 visitDeclarationContainernull92 override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: Unit) { 93 super.visitDeclarationContainer(declarationContainer, data) 94 } 95 visitDynamicReferencenull96 override fun visitDynamicReference(reference: KSDynamicReference, data: Unit) { 97 super.visitDynamicReference(reference, data) 98 } 99 visitFilenull100 override fun visitFile(file: KSFile, data: Unit) { 101 file.fileName 102 file.packageName 103 file.filePath 104 super.visitFile(file, data) 105 } 106 visitFunctionDeclarationnull107 override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) { 108 function.functionKind 109 function.isAbstract 110 function.findOverridee() 111 super.visitFunctionDeclaration(function, data) 112 } 113 visitModifierListOwnernull114 override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: Unit) { 115 modifierListOwner.modifiers 116 super.visitModifierListOwner(modifierListOwner, data) 117 } 118 visitNodenull119 override fun visitNode(node: KSNode, data: Unit) { 120 collectedNodes.add(node.origin.toString()) 121 collectedNodes.add(node.location.toString()) 122 super.visitNode(node, data) 123 } 124 visitParenthesizedReferencenull125 override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: Unit) { 126 super.visitParenthesizedReference(reference, data) 127 } 128 visitPropertyAccessornull129 override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: Unit) { 130 accessor.receiver 131 super.visitPropertyAccessor(accessor, data) 132 } 133 visitPropertyDeclarationnull134 override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) { 135 if (!property.isLocal()) { 136 property.isMutable 137 property.findOverridee() 138 property.isDelegated() 139 } 140 super.visitPropertyDeclaration(property, data) 141 } 142 visitPropertyGetternull143 override fun visitPropertyGetter(getter: KSPropertyGetter, data: Unit) { 144 super.visitPropertyGetter(getter, data) 145 } 146 visitPropertySetternull147 override fun visitPropertySetter(setter: KSPropertySetter, data: Unit) { 148 super.visitPropertySetter(setter, data) 149 } 150 visitReferenceElementnull151 override fun visitReferenceElement(element: KSReferenceElement, data: Unit) { 152 super.visitReferenceElement(element, data) 153 } 154 visitTypeAliasnull155 override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit) { 156 typeAlias.name 157 super.visitTypeAlias(typeAlias, data) 158 } 159 visitTypeArgumentnull160 override fun visitTypeArgument(typeArgument: KSTypeArgument, data: Unit) { 161 typeArgument.variance 162 super.visitTypeArgument(typeArgument, data) 163 } 164 visitTypeParameternull165 override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit) { 166 typeParameter.name 167 typeParameter.variance 168 typeParameter.isReified 169 super.visitTypeParameter(typeParameter, data) 170 } 171 visitTypeReferencenull172 override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) { 173 typeReference.resolve() 174 super.visitTypeReference(typeReference, data) 175 } 176 visitValueArgumentnull177 override fun visitValueArgument(valueArgument: KSValueArgument, data: Unit) { 178 valueArgument.name 179 valueArgument.isSpread 180 valueArgument.value 181 super.visitValueArgument(valueArgument, data) 182 } 183 visitValueParameternull184 override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) { 185 valueParameter.name 186 valueParameter.isCrossInline 187 valueParameter.isNoInline 188 valueParameter.isVal 189 valueParameter.isVar 190 valueParameter.isVararg 191 valueParameter.hasDefault 192 super.visitValueParameter(valueParameter, data) 193 } 194 } 195 } 196 197 class ExhaustiveProcessorProvider : SymbolProcessorProvider { createnull198 override fun create( 199 env: SymbolProcessorEnvironment 200 ): SymbolProcessor { 201 return ExhaustiveProcessor(env.codeGenerator, env.options) 202 } 203 } 204