blob: f0027c5b85a5f4771f41e6a31fe69082f01e0680 [file] [log] [blame]
Yigit Boyar6ab4a1f2021-06-30 09:53:33 -07001/*
2 * Copyright 2021 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
17package androidx.room.compiler.processing
18
19/**
Yigit Boyar6ab4a1f2021-06-30 09:53:33 -070020 * see [XTypeElement.getAllFieldsIncludingPrivateSupers]
21 */
22internal fun collectFieldsIncludingPrivateSupers(
23 xTypeElement: XTypeElement
24): Sequence<XFieldElement> {
bcorsod2a22722021-10-01 10:43:33 -070025 return sequence {
26 val existingFieldNames = mutableSetOf<String>()
bcorsoeafa45b2021-10-01 17:15:07 -070027 suspend fun SequenceScope<XFieldElement>.yieldAllFields(type: XTypeElement) {
28 // yield all fields declared directly on this type
29 type.getDeclaredFields().forEach {
bcorsod2a22722021-10-01 10:43:33 -070030 if (existingFieldNames.add(it.name)) {
bcorsoeafa45b2021-10-01 17:15:07 -070031 if (type == xTypeElement) {
32 yield(it)
33 } else {
34 yield(it.copyTo(xTypeElement))
35 }
bcorsod2a22722021-10-01 10:43:33 -070036 }
37 }
bcorsoeafa45b2021-10-01 17:15:07 -070038 // visit all declared fields on super types
39 type.superType?.typeElement?.let { parent ->
40 yieldAllFields(parent)
41 }
bcorsod2a22722021-10-01 10:43:33 -070042 }
bcorsoeafa45b2021-10-01 17:15:07 -070043 yieldAllFields(xTypeElement)
bcorsod2a22722021-10-01 10:43:33 -070044 }
Yigit Boyar6ab4a1f2021-06-30 09:53:33 -070045}
46
47/**
48 * see [XTypeElement.getAllMethods]
49 */
50internal fun collectAllMethods(
51 xTypeElement: XTypeElement
52): Sequence<XMethodElement> {
bcorsod2a22722021-10-01 10:43:33 -070053 return sequence {
Yigit Boyarc1eb02a2022-01-13 16:11:00 -080054 // group methods by name for faster override checks. Note that we are using name here
55 // instead of jvmName because resolving jvmName is expensive and @JvmName is not allowed on
56 // overriding methods or open methods (unless suppressed, which we don't support).
57 // As a result of this, name is as good as jvmName for grouping.
bcorsod2a22722021-10-01 10:43:33 -070058 val methodsByName = mutableMapOf<String, LinkedHashSet<XMethodElement>>()
bcorsoeafa45b2021-10-01 17:15:07 -070059 val visitedInterfaces = mutableSetOf<XTypeElement>()
bcorsod2a22722021-10-01 10:43:33 -070060 fun collectAllMethodsByName(type: XTypeElement) {
bcorsod2a22722021-10-01 10:43:33 -070061 // First, visit all super interface methods.
62 type.getSuperInterfaceElements().forEach {
bcorsoeafa45b2021-10-01 17:15:07 -070063 // Skip if we've already visited the methods in this interface.
64 if (visitedInterfaces.add(it)) {
65 collectAllMethodsByName(it)
66 }
bcorsod2a22722021-10-01 10:43:33 -070067 }
68 // Next, visit all super class methods.
69 type.superType?.typeElement?.let {
70 collectAllMethodsByName(it)
71 }
72 // Finally, visit all methods declared in this type.
73 if (type == xTypeElement) {
74 type.getDeclaredMethods().forEach {
Yigit Boyarc1eb02a2022-01-13 16:11:00 -080075 methodsByName.getOrPut(it.name) { linkedSetOf() }.add(it)
bcorsod2a22722021-10-01 10:43:33 -070076 }
77 } else {
78 type.getDeclaredMethods()
79 .filter { it.isAccessibleFrom(type.packageName) }
80 .filterNot { it.isStaticInterfaceMethod() }
81 .map { it.copyTo(xTypeElement) }
Yigit Boyarc1eb02a2022-01-13 16:11:00 -080082 .forEach {
83 methodsByName.getOrPut(it.name) { linkedSetOf() }.add(it)
84 }
bcorsod2a22722021-10-01 10:43:33 -070085 }
86 }
87 collectAllMethodsByName(xTypeElement)
88
89 // Yield all non-overridden methods
90 methodsByName.values.forEach { methodSet ->
91 if (methodSet.size == 1) {
92 // There's only one method with this name, so it can't be overridden
93 yield(methodSet.single())
94 } else {
95 // There are multiple methods with the same name, so we must check for overridden
96 // methods. The order of the methods should guarantee that any potentially
97 // overridden method comes first in the list, so we only need to check each method
98 // against subsequent methods.
99 val methods = methodSet.toList()
100 val overridden = mutableSetOf<XMethodElement>()
101 methods.forEachIndexed { i, methodOne ->
102 methods.subList(i + 1, methods.size).forEach { methodTwo ->
103 if (methodTwo.overrides(methodOne, xTypeElement)) {
104 overridden.add(methodOne)
bcorsoeafa45b2021-10-01 17:15:07 -0700105 // Once we've added methodOne, we can break out of this inner loop since
106 // additional checks would only try to add methodOne again.
bcorsod2a22722021-10-01 10:43:33 -0700107 return@forEachIndexed
108 }
109 }
110 }
111 methods.filterNot { overridden.contains(it) }.forEach { yield(it) }
112 }
113 }
114 }
115}
116
117private fun XMethodElement.isAccessibleFrom(packageName: String): Boolean {
118 if (isPublic() || isProtected()) {
119 return true
120 }
121 if (isPrivate()) {
122 return false
123 }
124 // check package
125 return packageName == enclosingElement.className.packageName()
126}
127
128private fun XMethodElement.isStaticInterfaceMethod(): Boolean {
129 return isStatic() && (enclosingElement as? XTypeElement)?.isInterface() == true
130}