1 /*
<lambda>null2 * Copyright (C) 2021 Square, Inc.
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 * https://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 package com.squareup.kotlinpoet.ksp
17
18 import com.google.devtools.ksp.symbol.KSType
19 import com.google.devtools.ksp.symbol.KSTypeParameter
20 import com.squareup.kotlinpoet.TypeVariableName
21
22 /**
23 * A resolver for enclosing declarations' type parameters. Parent declarations can be anything with
24 * generics that child nodes declare as defined by [KSType.arguments].
25 *
26 * This is important for resolving inherited generics on child declarations, as KSP interop
27 * otherwise can't resolve them.
28 *
29 * In general, you want to retrieve an instance of this via [toTypeParameterResolver].
30 *
31 * @see toTypeParameterResolver
32 */
33 public interface TypeParameterResolver {
34 public val parametersMap: Map<String, TypeVariableName>
35 public operator fun get(index: String): TypeVariableName
36
37 public companion object {
38 /**
39 * An empty instance of [TypeParameterResolver], only should be used if enclosing declarations
40 * are known to not have arguments, such as top-level classes.
41 */
42 public val EMPTY: TypeParameterResolver = object : TypeParameterResolver {
43 override val parametersMap: Map<String, TypeVariableName> = emptyMap()
44
45 override fun get(index: String): TypeVariableName = throw NoSuchElementException("No TypeParameter found for index $index")
46 }
47 }
48 }
49
50 /**
51 * Returns a [TypeParameterResolver] for this list of [KSTypeParameters][KSTypeParameter] for use
52 * with enclosed declarations.
53 *
54 * @param parent the optional parent resolver, if any. An example of this is cases where you might
55 * create a resolver for a [KSFunction] and supply a parent resolved from the
56 * enclosing [KSClassDeclaration].
57 * @param sourceTypeHint an optional hint for error messages. Unresolvable parameter IDs will
58 * include this hint in the thrown error's message.
59 */
toTypeParameterResolvernull60 public fun List<KSTypeParameter>.toTypeParameterResolver(
61 parent: TypeParameterResolver? = null,
62 sourceTypeHint: String = "<unknown>",
63 ): TypeParameterResolver {
64 val parametersMap = LinkedHashMap<String, TypeVariableName>()
65 val typeParamResolver = { id: String ->
66 parametersMap[id]
67 ?: parent?.get(id)
68 ?: throw IllegalStateException(
69 "No type argument found for $id! Analyzed $sourceTypeHint with known parameters " +
70 "${parametersMap.keys}",
71 )
72 }
73
74 val resolver = object : TypeParameterResolver {
75 override val parametersMap: Map<String, TypeVariableName> = parametersMap
76
77 override operator fun get(index: String): TypeVariableName = typeParamResolver(index)
78 }
79
80 // Fill the parametersMap. Need to do sequentially and allow for referencing previously defined params
81 for (typeVar in this) {
82 // Put the simple typevar in first, then it can be referenced in the full toTypeVariable()
83 // replacement later that may add bounds referencing this.
84 val id = typeVar.name.getShortName()
85 parametersMap[id] = TypeVariableName(id)
86 }
87
88 for (typeVar in this) {
89 val id = typeVar.name.getShortName()
90 // Now replace it with the full version.
91 parametersMap[id] = typeVar.toTypeVariableName(resolver)
92 }
93
94 return resolver
95 }
96