xref: /aosp_15_r20/external/ksp/api/src/main/kotlin/com/google/devtools/ksp/processing/CodeGenerator.kt (revision af87fb4bb8e3042070d2a054e912924f599b22b7)
1 /*
2  * Copyright 2020 Google LLC
3  * Copyright 2010-2020 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 package com.google.devtools.ksp.processing
18 
19 import com.google.devtools.ksp.symbol.*
20 import java.io.File
21 import java.io.OutputStream
22 
23 /**
24  * [CodeGenerator] creates and manages files.
25  *
26  * Files created by [CodeGenerator] are considered in incremental processing.
27  * Kotlin and Java files will be compiled together with other source files in the module.
28  * Files created without using this API will not participate in incremental processing nor subsequent compilations.
29  */
30 interface CodeGenerator {
31     /**
32      * Creates a file which is managed by [CodeGenerator]
33      *
34      * Sources of corresponding [KSNode]s which are obtained directly from [Resolver] need to be specified.
35      * Namely, the containing files of those [KSNode]s who are obtained from:
36      *   * [Resolver.getAllFiles]
37      *   * [Resolver.getSymbolsWithAnnotation]
38      *   * [Resolver.getClassDeclarationByName]
39      *
40      * Instead of requiring processors to specify all source files which are relevant in generating the given output,
41      * KSP traces dependencies automatically and only needs to know those sources that only processors know what they
42      * are for. If a [KSFile] is indirectly obtained through other [KSNode]s, it hasn't to be specified for the given
43      * output, even if its contents contribute to the generation of the output.
44      *
45      * For example, a processor generates an output `O` after reading class `A` in `A.kt` and class `B` in `B.kt`,
46      * where `A` extends `B`. The processor got `A` by [Resolver.getSymbolsWithAnnotation] and then got `B` by
47      * [KSClassDeclaration.superTypes] from `A`. Because the inclusion of `B` is due to `A`, `B.kt` needn't to be
48      * specified in [dependencies] for `O`. Note that specifying `B.kt` in this case doesn't hurt, it is only unnecessary.
49      *
50      * @param dependencies are [KSFile]s from which this output is built. Only those that are obtained directly
51      *                     from [Resolver] are required.
52      * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
53      * @param fileName file name
54      * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
55      *                      Otherwise its creation is only considered in incremental processing.
56      * @return OutputStream for writing into files.
57      * @see [CodeGenerator] for more details.
58      */
createNewFilenull59     fun createNewFile(
60         dependencies: Dependencies,
61         packageName: String,
62         fileName: String,
63         extensionName: String = "kt"
64     ): OutputStream
65 
66     /**
67      * Creates a file which is managed by [CodeGenerator]
68      *
69      * Sources of corresponding [KSNode]s which are obtained directly from [Resolver] need to be specified.
70      * Namely, the containing files of those [KSNode]s who are obtained from:
71      *   * [Resolver.getAllFiles]
72      *   * [Resolver.getSymbolsWithAnnotation]
73      *   * [Resolver.getClassDeclarationByName]
74      *
75      * Instead of requiring processors to specify all source files which are relevant in generating the given output,
76      * KSP traces dependencies automatically and only needs to know those sources that only processors know what they
77      * are for. If a [KSFile] is indirectly obtained through other [KSNode]s, it hasn't to be specified for the given
78      * output, even if its contents contribute to the generation of the output.
79      *
80      * For example, a processor generates an output `O` after reading class `A` in `A.kt` and class `B` in `B.kt`,
81      * where `A` extends `B`. The processor got `A` by [Resolver.getSymbolsWithAnnotation] and then got `B` by
82      * [KSClassDeclaration.superTypes] from `A`. Because the inclusion of `B` is due to `A`, `B.kt` needn't to be
83      * specified in [dependencies] for `O`. Note that specifying `B.kt` in this case doesn't hurt, it is only unnecessary.
84      *
85      * @param dependencies are [KSFile]s from which this output is built. Only those that are obtained directly
86      *                     from [Resolver] are required.
87      * @param path corresponds to the relative path of the generated file; includes the full file name
88      * @param fileType determines the target directory to store the file
89      * @return OutputStream for writing into files.
90      * @see [CodeGenerator] for more details.
91      */
92     fun createNewFileByPath(
93         dependencies: Dependencies,
94         path: String,
95         extensionName: String = "kt"
96     ): OutputStream
97 
98     /**
99      * Associate [sources] to an output file.
100      *
101      * @param sources are [KSFile]s from which this output is built. Only those that are obtained directly
102      *                     from [Resolver] are required.
103      * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
104      * @param fileName file name
105      * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
106      *                      Otherwise its creation is only considered in incremental processing.
107      * @see [CodeGenerator] for more details.
108      */
109     fun associate(sources: List<KSFile>, packageName: String, fileName: String, extensionName: String = "kt")
110 
111     /**
112      * Associate [sources] to an output file.
113      *
114      * @param sources are [KSFile]s from which this output is built. Only those that are obtained directly
115      *                     from [Resolver] are required.
116      * @param path corresponds to the relative path of the generated file; includes the full file name
117      * @param fileType determines the target directory where the file should exist
118      * @see [CodeGenerator] for more details.
119      */
120     fun associateByPath(sources: List<KSFile>, path: String, extensionName: String = "kt")
121 
122     /**
123      * Associate [classes] to an output file.
124      *
125      * @param classes are [KSClassDeclaration]s from which this output is built. Only those that are obtained directly
126      *                     from [Resolver] are required.
127      * @param packageName corresponds to the relative path of the generated file; using either '.'or '/' as separator.
128      * @param fileName file name
129      * @param extensionName If "kt" or "java", this file will participate in subsequent compilation.
130      *                      Otherwise its creation is only considered in incremental processing.
131      * @see [CodeGenerator] for more details.
132      */
133     fun associateWithClasses(
134         classes: List<KSClassDeclaration>,
135         packageName: String,
136         fileName: String,
137         extensionName: String = "kt"
138     )
139 
140     val generatedFile: Collection<File>
141 }
142 
143 /**
144  * Dependencies of an output file.
145  */
146 class Dependencies private constructor(
147     val isAllSources: Boolean,
148     val aggregating: Boolean,
149     val originatingFiles: List<KSFile>
150 ) {
151 
152     /**
153      * Create a [Dependencies] to associate with an output.
154      *
155      * @param aggregating whether the output should be invalidated by a new source file or a change in any of the existing files.
156      *                           Namely, whenever there is new information.
157      * @param sources Sources for this output to depend on.
158      */
159     constructor(aggregating: Boolean, vararg sources: KSFile) : this(false, aggregating, sources.toList())
160 
161     companion object {
162         /**
163          * A short-hand to all source files.
164          *
165          * Associating an output to [ALL_SOURCES] essentially disables incremental processing, as the tiniest change will clobber all files.
166          * This should not be used in processors which care about processing speed.
167          */
168         val ALL_FILES = Dependencies(true, true, emptyList())
169     }
170 }
171