1 /* 2 * Copyright 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.appfunctions.compiler 18 19 import androidx.appfunctions.compiler.core.AnnotatedAppFunctions 20 import androidx.appfunctions.compiler.core.AppFunctionSymbolResolver 21 import androidx.appfunctions.compiler.core.ProcessingException 22 import androidx.appfunctions.compiler.core.SymbolNotReadyException 23 import androidx.appfunctions.compiler.core.logException 24 import androidx.appfunctions.compiler.processors.AppFunctionAggregateProcessor 25 import androidx.appfunctions.compiler.processors.AppFunctionFunctionRegistryProcessor 26 import androidx.appfunctions.compiler.processors.AppFunctionIdProcessor 27 import androidx.appfunctions.compiler.processors.AppFunctionInventoryProcessor 28 import androidx.appfunctions.compiler.processors.AppFunctionInvokerProcessor 29 import androidx.appfunctions.compiler.processors.AppFunctionSerializableProcessor 30 import com.google.devtools.ksp.processing.KSPLogger 31 import com.google.devtools.ksp.processing.Resolver 32 import com.google.devtools.ksp.processing.SymbolProcessor 33 import com.google.devtools.ksp.processing.SymbolProcessorEnvironment 34 import com.google.devtools.ksp.processing.SymbolProcessorProvider 35 import com.google.devtools.ksp.symbol.KSAnnotated 36 import com.squareup.kotlinpoet.AnnotationSpec 37 import javax.annotation.processing.Generated 38 39 /** The compiler to process AppFunction implementations. */ 40 class AppFunctionCompiler( 41 private val processors: List<SymbolProcessor>, 42 private val logger: KSPLogger, 43 ) : SymbolProcessor { 44 processnull45 override fun process(resolver: Resolver): List<KSAnnotated> { 46 return try { 47 val deferred = shouldDeferAllProcessing(resolver) 48 if (deferred.isNotEmpty()) { 49 deferred 50 } else { 51 buildList { 52 for (processor in processors) { 53 addAll(processor.process(resolver)) 54 } 55 } 56 } 57 } catch (e: ProcessingException) { 58 logger.logException(e) 59 emptyList() 60 } 61 } 62 63 /** 64 * Returns a non-empty list of [KSAnnotated] nodes if the processor should defer all these 65 * symbols. 66 * 67 * To ensure that all generated components are recorded in AppFunctionComponentRegistry in each 68 * compilation unit, the processor should start the processing only when all the nodes are 69 * ready. 70 */ shouldDeferAllProcessingnull71 private fun shouldDeferAllProcessing(resolver: Resolver): List<KSAnnotated> { 72 val appFunctionSymbolResolver = AppFunctionSymbolResolver(resolver) 73 val annotatedAppFunctions = appFunctionSymbolResolver.resolveAnnotatedAppFunctions() 74 for (annotatedAppFunction in annotatedAppFunctions) { 75 try { 76 annotatedAppFunction.validate() 77 } catch (e: SymbolNotReadyException) { 78 logger.logging(e.message.toString(), e.node) 79 return annotatedAppFunctions.flatMap(AnnotatedAppFunctions::getAllAnnotated) 80 } 81 } 82 return emptyList() 83 } 84 85 class Provider : SymbolProcessorProvider { 86 createnull87 override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { 88 val options = AppFunctionCompilerOptions.from(environment.options) 89 90 val functionRegistryProcessor = 91 AppFunctionFunctionRegistryProcessor(environment.codeGenerator) 92 val idProcessor = AppFunctionIdProcessor(environment.codeGenerator) 93 val inventoryProcessor = AppFunctionInventoryProcessor(environment.codeGenerator) 94 val invokerProcessor = AppFunctionInvokerProcessor(environment.codeGenerator) 95 val entityProcessor = 96 AppFunctionSerializableProcessor(environment.codeGenerator, environment.logger) 97 val aggregateProcessor = 98 AppFunctionAggregateProcessor(options, environment.codeGenerator) 99 return AppFunctionCompiler( 100 listOf( 101 functionRegistryProcessor, 102 idProcessor, 103 inventoryProcessor, 104 invokerProcessor, 105 entityProcessor, 106 aggregateProcessor, 107 ), 108 environment.logger, 109 ) 110 } 111 } 112 113 companion object { 114 internal val GENERATED_ANNOTATION = 115 AnnotationSpec.builder(Generated::class) 116 .addMember("%S", AppFunctionCompiler::class.java.canonicalName) 117 .build() 118 } 119 } 120