113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/*
213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Copyright (C) 2017 The Android Open Source Project
313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar *
413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * you may not use this file except in compliance with the License.
613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * You may obtain a copy of the License at
713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar *
813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar *
1013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Unless required by applicable law or agreed to in writing, software
1113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * See the License for the specific language governing permissions and
1413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * limitations under the License.
1513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */
1613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.room.processor
18ba069d50913c3fb250bb60ec310439db36895337Alan Viverette
19ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ColumnInfo
20ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.Embedded
21ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.Ignore
22ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.Relation
23ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.KotlinMetadataProcessor
2426038b2b81caa477ba65593de1d7ea370cbe6a0bYigit Boyarimport androidx.room.ext.extendsBoundOrSelf
25ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.getAllFieldsIncludingPrivateSupers
26ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.getAnnotationValue
27ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.getAsString
28ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.getAsStringList
29ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.hasAnnotation
30ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.hasAnyOf
31ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.isAssignableWithoutVariance
32ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.isCollection
33ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.toClassType
34ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.ext.typeName
35ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD
36ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.processor.ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD
37ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.processor.ProcessorErrors.CANNOT_FIND_TYPE
38ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.processor.ProcessorErrors.POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME
39ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.processor.cache.Cache
40ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.CallType
41ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.Constructor
42ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.EmbeddedField
43ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.Entity
44ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.Field
45ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.FieldGetter
46ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.FieldSetter
47ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.Pojo
48ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.PojoMethod
49ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.vo.Warning
50092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport com.google.auto.common.AnnotationMirrors
5113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreElements
5213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreTypes
539e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyarimport me.eugeniomarletti.kotlin.metadata.KotlinClassMetadata
549e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyarimport me.eugeniomarletti.kotlin.metadata.kotlinMetadata
559e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyarimport javax.annotation.processing.ProcessingEnvironment
5613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.ExecutableElement
5713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.ABSTRACT
5813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.PRIVATE
595bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PROTECTED
605bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PUBLIC
6113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.STATIC
62a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyarimport javax.lang.model.element.Modifier.TRANSIENT
631a74519922de68e007027d56aae9370ee21f31f9shepshapardimport javax.lang.model.element.Name
6413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.TypeElement
65092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport javax.lang.model.element.VariableElement
6696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.type.DeclaredType
6713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.type.TypeKind
685bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.type.TypeMirror
69f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyarimport javax.lang.model.util.ElementFilter
7013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
7113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/**
7213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Processes any class as if it is a Pojo.
7313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */
74757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyarclass PojoProcessor(
75757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        baseContext: Context,
76757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        val element: TypeElement,
77757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        val bindingScope: FieldProcessor.BindingScope,
78757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        val parent: EmbeddedField?,
79757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        val referenceStack: LinkedHashSet<Name> = LinkedHashSet())
8083d1d1ecd4ec87a0fa90e3e8367c7a48e8bf6e33Yigit Boyar    : KotlinMetadataProcessor {
81aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar    val context = baseContext.fork(element)
829e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
839e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    // for KotlinMetadataUtils
849e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    override val processingEnv: ProcessingEnvironment
859e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        get() = context.processingEnv
869e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
879e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    // opportunistic kotlin metadata
889e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    private val kotlinMetadata by lazy {
899e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        try {
909e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            element.kotlinMetadata
919e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        } catch (throwable: Throwable) {
929e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            context.logger.d(element, "failed to read get kotlin metadata from %s", element)
9383d1d1ecd4ec87a0fa90e3e8367c7a48e8bf6e33Yigit Boyar        } as? KotlinClassMetadata
949e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    }
959e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
96092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    companion object {
974d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class,
989e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                Relation::class)
99092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
1009e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
1016f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun process(): Pojo {
1025124503104860e68981cc3e3092b95932586f66fYigit Boyar        return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), {
1031a74519922de68e007027d56aae9370ee21f31f9shepshapard            referenceStack.add(element.qualifiedName)
1041a74519922de68e007027d56aae9370ee21f31f9shepshapard            try {
1051a74519922de68e007027d56aae9370ee21f31f9shepshapard                doProcess()
1066f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            } finally {
1071a74519922de68e007027d56aae9370ee21f31f9shepshapard                referenceStack.remove(element.qualifiedName)
1081a74519922de68e007027d56aae9370ee21f31f9shepshapard            }
1095124503104860e68981cc3e3092b95932586f66fYigit Boyar        })
1105124503104860e68981cc3e3092b95932586f66fYigit Boyar    }
1115124503104860e68981cc3e3092b95932586f66fYigit Boyar
1125124503104860e68981cc3e3092b95932586f66fYigit Boyar    private fun doProcess(): Pojo {
11313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val declaredType = MoreTypes.asDeclared(element.asType())
11496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        // TODO handle conflicts with super: b/35568142
11596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val allFields = element.getAllFieldsIncludingPrivateSupers(context.processingEnv)
11613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
117a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                    !it.hasAnnotation(Ignore::class)
118a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                            && !it.hasAnyOf(STATIC)
119a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                            && (!it.hasAnyOf(TRANSIENT)
1209e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                            || it.hasAnnotation(ColumnInfo::class)
1219e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                            || it.hasAnnotation(Embedded::class)
1229e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                            || it.hasAnnotation(Relation::class))
12396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
124092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .groupBy { field ->
125092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.checker.check(
126092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            PROCESSED_ANNOTATIONS.count { field.hasAnnotation(it) } < 2, field,
127092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION
128092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    )
1294d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    if (field.hasAnnotation(Embedded::class)) {
1304d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Embedded::class
131092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else if (field.hasAnnotation(Relation::class)) {
132092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        Relation::class
133092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else {
134092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        null
135092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    }
136092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
1371a74519922de68e007027d56aae9370ee21f31f9shepshapard
138092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myFields = allFields[null]
139092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
14096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    FieldProcessor(
14196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            baseContext = context,
14296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            containing = declaredType,
14396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            element = it,
14496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            bindingScope = bindingScope,
14596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            fieldParent = parent).process()
146092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                } ?: emptyList()
147092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1481a74519922de68e007027d56aae9370ee21f31f9shepshapard        val embeddedFields =
1491a74519922de68e007027d56aae9370ee21f31f9shepshapard                allFields[Embedded::class]
150c21394d1dcb24518061aabde879baff891a426e3Sergey Vasilinets                        ?.mapNotNull {
1511a74519922de68e007027d56aae9370ee21f31f9shepshapard                            processEmbeddedField(declaredType, it)
1521a74519922de68e007027d56aae9370ee21f31f9shepshapard                        }
1531a74519922de68e007027d56aae9370ee21f31f9shepshapard                        ?: emptyList()
15413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
1551a74519922de68e007027d56aae9370ee21f31f9shepshapard        val subFields = embeddedFields.flatMap { it.pojo.fields }
15696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val fields = myFields + subFields
157092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
158092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myRelationsList = allFields[Relation::class]
159c21394d1dcb24518061aabde879baff891a426e3Sergey Vasilinets                ?.mapNotNull {
160092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    processRelationField(fields, declaredType, it)
161092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
1621a74519922de68e007027d56aae9370ee21f31f9shepshapard                ?: emptyList()
163092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1644d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subRelations = embeddedFields.flatMap { it.pojo.relations }
165092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val relations = myRelationsList + subRelations
166092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
16796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        fields.groupBy { it.columnName }
16896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .filter { it.value.size > 1 }
16996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .forEach {
17096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    context.logger.e(element, ProcessorErrors.pojoDuplicateFieldNames(
17196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            it.key, it.value.map(Field::getPath)
17296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    ))
17396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    it.value.forEach {
17496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        context.logger.e(it.element, POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME)
17596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    }
17696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
1771a74519922de68e007027d56aae9370ee21f31f9shepshapard
17896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val methods = MoreElements.getLocalAndInheritedMethods(element,
17996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                context.processingEnv.elementUtils)
18013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
18196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC)
18213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                            && !it.hasAnnotation(Ignore::class)
18313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
18413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .map { MoreElements.asExecutable(it) }
185757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                .map {
186757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    PojoMethodProcessor(
187757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            context = context,
188757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            element = it,
189757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            owner = declaredType
190757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    ).process()
191757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                }
19213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
19313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val getterCandidates = methods.filter {
194757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            it.element.parameters.size == 0 && it.resolvedType.returnType.kind != TypeKind.VOID
19513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
19613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
19713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val setterCandidates = methods.filter {
198757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            it.element.parameters.size == 1 && it.resolvedType.returnType.kind == TypeKind.VOID
19913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
2001a74519922de68e007027d56aae9370ee21f31f9shepshapard
201f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        // don't try to find a constructor for binding to statement.
202f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructor = if (bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT) {
203f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            // we don't need to construct this POJO.
204f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            null
205f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        } else {
20637a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar            chooseConstructor(myFields, embeddedFields, relations)
207f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
20813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
20996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        assignGetters(myFields, getterCandidates)
210f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        assignSetters(myFields, setterCandidates, constructor)
211092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
2124d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        embeddedFields.forEach {
213092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
214f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
215092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
216092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
217092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        myRelationsList.forEach {
218092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
219f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
220092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
221092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
2221a74519922de68e007027d56aae9370ee21f31f9shepshapard        return Pojo(element = element,
22396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                type = declaredType,
22496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                fields = fields,
2254d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                embeddedFields = embeddedFields,
226f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                relations = relations,
227f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                constructor = constructor)
22813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
22913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
2309e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    /**
2319e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * Retrieves the parameter names of a method. If the method is inherited from a dependency
2329e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * module, the parameter name is not available (not in java spec). For kotlin, since parameter
2339e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * names are part of the API, we can read them via the kotlin metadata annotation.
2349e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * <p>
2359e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * Since we are using an unofficial library to read the metadata, all access to that code
2369e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * is safe guarded to avoid unexpected failures. In other words, it is a best effort but
2379e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     * better than not supporting these until JB provides a proper API.
2389e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar     */
2399e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    private fun getParamNames(method: ExecutableElement): List<String> {
2409e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        val paramNames = method.parameters.map { it.simpleName.toString() }
2419e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        if (paramNames.isEmpty()) {
2429e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            return emptyList()
2439e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        }
24483d1d1ecd4ec87a0fa90e3e8367c7a48e8bf6e33Yigit Boyar        return kotlinMetadata?.getParameterNames(method) ?: paramNames
2459e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    }
2469e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
2476f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private fun chooseConstructor(
24837a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar            myFields: List<Field>,
24937a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar            embedded: List<EmbeddedField>,
250ba069d50913c3fb250bb60ec310439db36895337Alan Viverette            relations: List<androidx.room.vo.Relation>): Constructor? {
251f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructors = ElementFilter.constructorsIn(element.enclosedElements)
252f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                .filterNot { it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE) }
253f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val fieldMap = myFields.associateBy { it.name }
2544d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedMap = embedded.associateBy { it.field.name }
255f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val typeUtils = context.processingEnv.typeUtils
2569e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        // list of param names -> matched params pairs for each failed constructor
2579e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        val failedConstructors = arrayListOf<FailedConstructor>()
2585cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar        // if developer puts a relation into a constructor, it is usually an error but if there
2595cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar        // is another constructor that is good, we can ignore the error. b/72884434
2605cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar        val relationsInConstructor = arrayListOf<VariableElement>()
261f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val goodConstructors = constructors.map { constructor ->
2629e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val parameterNames = getParamNames(constructor)
2639e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val params = constructor.parameters.mapIndexed param@ { index, param ->
2649e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                val paramName = parameterNames[index]
265f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val paramType = param.asType()
266f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
267f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matches = fun(field: Field?): Boolean {
268f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return if (field == null) {
269f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
270f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else if (!field.nameWithVariations.contains(paramName)) {
271f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
272f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
2732fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar                        // see: b/69164099
2742fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar                        typeUtils.isAssignableWithoutVariance(paramType, field.type)
275f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
276f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
277f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
278f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val exactFieldMatch = fieldMap[paramName]
279f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
280f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                if (matches(exactFieldMatch)) {
281f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return@param Constructor.FieldParam(exactFieldMatch!!)
282f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2834d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val exactEmbeddedMatch = embeddedMap[paramName]
2844d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matches(exactEmbeddedMatch?.field)) {
2854d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    return@param Constructor.EmbeddedParam(exactEmbeddedMatch!!)
286f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
287f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
288f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matchingFields = myFields.filter {
289f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it)
290f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2914d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val embeddedMatches = embedded.filter {
292f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it.field)
293f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2944d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matchingFields.isEmpty() && embeddedMatches.isEmpty()) {
29537a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    // if it didn't match a proper field, a common mistake is to have a relation
29637a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    // so check to see if it is a relation
29737a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    val matchedRelation = relations.any {
29837a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                        it.field.nameWithVariations.contains(paramName)
29937a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    }
30037a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    if (matchedRelation) {
3015cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                        relationsInConstructor.add(param)
30237a4c4d3e29de0fa914c0496cafe0fca26de8bbfYigit Boyar                    }
303f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
3044d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                } else if (matchingFields.size + embeddedMatches.size == 1) {
305f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    if (matchingFields.isNotEmpty()) {
306f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        Constructor.FieldParam(matchingFields.first())
307f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
3084d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Constructor.EmbeddedParam(embeddedMatches.first())
309f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
310f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                } else {
311f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    context.logger.e(param, ProcessorErrors.ambigiousConstructor(
312f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            pojo = element.qualifiedName.toString(),
3139e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                            paramName = paramName,
314f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            matchingFields = matchingFields.map { it.getPath() }
3154d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                                    + embedded.map { it.field.getPath() }
316f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    ))
317f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
318f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
319f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
320f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            if (params.any { it == null }) {
3219e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                failedConstructors.add(FailedConstructor(constructor, parameterNames, params))
322f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                null
323f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            } else {
324f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                @Suppress("UNCHECKED_CAST")
325f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                Constructor(constructor, params as List<Constructor.Param>)
326f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
327f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }.filterNotNull()
3285cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar        when {
3295cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar            goodConstructors.isEmpty() -> {
3305cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                relationsInConstructor.forEach {
3315cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    context.logger.e(it,
3325cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                            ProcessorErrors.RELATION_CANNOT_BE_CONSTRUCTOR_PARAMETER)
333f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
3345cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                if (failedConstructors.isNotEmpty()) {
3355cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    val failureMsg = failedConstructors.joinToString("\n") { entry ->
3365cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                        entry.log()
3375cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    }
3385cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR +
3395cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                            "\nTried the following constructors but they failed to match:" +
3405cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                            "\n$failureMsg")
3415cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                }
3425cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
3435cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                return null
344b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar            }
3455cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar            goodConstructors.size > 1 -> {
3465cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                // if there is a no-arg constructor, pick it. Even though it is weird, easily happens
3475cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                // with kotlin data classes.
3485cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                val noArg = goodConstructors.firstOrNull { it.params.isEmpty() }
3495cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                if (noArg != null) {
3505cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element,
3515cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                            ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
3525cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    return noArg
3535cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                }
3545cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                goodConstructors.forEach {
3555cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                    context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
3565cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                }
3575cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar                return null
358f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
3595cd20c98ceefcf9a2547cb421607d25596433fd5Yigit Boyar            else -> return goodConstructors.first()
360f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
361f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    }
362f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
3636f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private fun processEmbeddedField(
3646f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            declaredType: DeclaredType?, variableElement: VariableElement): EmbeddedField? {
36553bd414cca00f4d7172b6caba513a477195bed47Yigit Boyar        val asMemberType = MoreTypes.asMemberOf(
36653bd414cca00f4d7172b6caba513a477195bed47Yigit Boyar            context.processingEnv.typeUtils, declaredType, variableElement)
36753bd414cca00f4d7172b6caba513a477195bed47Yigit Boyar        val asTypeElement = MoreTypes.asTypeElement(asMemberType)
3681a74519922de68e007027d56aae9370ee21f31f9shepshapard
3691a74519922de68e007027d56aae9370ee21f31f9shepshapard        if (detectReferenceRecursion(asTypeElement)) {
3701a74519922de68e007027d56aae9370ee21f31f9shepshapard            return null
3711a74519922de68e007027d56aae9370ee21f31f9shepshapard        }
3721a74519922de68e007027d56aae9370ee21f31f9shepshapard
3731a74519922de68e007027d56aae9370ee21f31f9shepshapard        val fieldPrefix = variableElement
3741a74519922de68e007027d56aae9370ee21f31f9shepshapard                .getAnnotationValue(Embedded::class.java, "prefix")
3751a74519922de68e007027d56aae9370ee21f31f9shepshapard                ?.toString()
3761a74519922de68e007027d56aae9370ee21f31f9shepshapard                ?: ""
37796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val inheritedPrefix = parent?.prefix ?: ""
3786f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas        val embeddedField = Field(
3796f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas                variableElement,
3806f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas                variableElement.simpleName.toString(),
38153bd414cca00f4d7172b6caba513a477195bed47Yigit Boyar                type = asMemberType,
3826f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas                affinity = null,
3836f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas                parent = parent)
3844d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subParent = EmbeddedField(
3854d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                field = embeddedField,
38696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                prefix = inheritedPrefix + fieldPrefix,
38796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                parent = parent)
3881a74519922de68e007027d56aae9370ee21f31f9shepshapard        subParent.pojo = PojoProcessor(
3891a74519922de68e007027d56aae9370ee21f31f9shepshapard                baseContext = context.fork(variableElement),
3901a74519922de68e007027d56aae9370ee21f31f9shepshapard                element = asTypeElement,
39196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                bindingScope = bindingScope,
3921a74519922de68e007027d56aae9370ee21f31f9shepshapard                parent = subParent,
3931a74519922de68e007027d56aae9370ee21f31f9shepshapard                referenceStack = referenceStack).process()
39496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        return subParent
39596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    }
39696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
3976f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private fun processRelationField(
3986f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            myFields: List<Field>, container: DeclaredType?,
3996f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            relationElement: VariableElement
400ba069d50913c3fb250bb60ec310439db36895337Alan Viverette    ): androidx.room.vo.Relation? {
40187a16a53f9806fe8bcbe4e3bef751fc214a4235aAurimas Liutikas        val asTypeElement = MoreTypes.asTypeElement(
40287a16a53f9806fe8bcbe4e3bef751fc214a4235aAurimas Liutikas                MoreElements.asVariable(relationElement).asType())
4031a74519922de68e007027d56aae9370ee21f31f9shepshapard
4041a74519922de68e007027d56aae9370ee21f31f9shepshapard        if (detectReferenceRecursion(asTypeElement)) {
4051a74519922de68e007027d56aae9370ee21f31f9shepshapard            return null
4061a74519922de68e007027d56aae9370ee21f31f9shepshapard        }
4071a74519922de68e007027d56aae9370ee21f31f9shepshapard
408092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val annotation = MoreElements.getAnnotationMirror(relationElement, Relation::class.java)
409092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .orNull()!!
410f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val parentColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "parentColumn")
411092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString("") ?: ""
412092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
413092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val parentField = myFields.firstOrNull {
414f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == parentColumnInput
415092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
416092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (parentField == null) {
417092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
418092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindParentEntityField(
419092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = element.qualifiedName.toString(),
420f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = parentColumnInput,
421f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = myFields.map { it.columnName }))
422092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
423092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
424092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // parse it as an entity.
425092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val asMember = MoreTypes
426092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .asMemberOf(context.processingEnv.typeUtils, container, relationElement)
427092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (asMember.kind == TypeKind.ERROR) {
428092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(ProcessorErrors.CANNOT_FIND_TYPE, element)
429092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
430092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
431092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val declared = MoreTypes.asDeclared(asMember)
432092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (!declared.isCollection()) {
433092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement, ProcessorErrors.RELATION_NOT_COLLECTION)
434092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
435092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
4365e4d488036d51131bf4c97102fed7905d88d086dYigit Boyar        val typeArg = declared.typeArguments.first().extendsBoundOrSelf()
437092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (typeArg.kind == TypeKind.ERROR) {
438092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(MoreTypes.asTypeElement(typeArg), CANNOT_FIND_TYPE)
439092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
440092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
441092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val typeArgElement = MoreTypes.asTypeElement(typeArg)
442092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityClassInput = AnnotationMirrors
443092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAnnotationValue(annotation, "entity").toClassType()
4443ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar
4453ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        // do we need to decide on the entity?
4463ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        val inferEntity = (entityClassInput == null
4473ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                || MoreTypes.isTypeOf(Any::class.java, entityClassInput))
4483ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar
4493ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        val entity = if (inferEntity) {
4503ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            EntityProcessor(context, typeArgElement, referenceStack).process()
451092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        } else {
4523ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput),
4536f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas                    referenceStack).process()
454092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
4553ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar
456092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // now find the field in the entity.
457f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val entityColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "entityColumn")
458092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString() ?: ""
459092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityField = entity.fields.firstOrNull {
460f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == entityColumnInput
461092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
462092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
463092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (entityField == null) {
464092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
465092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindEntityField(
466092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = entity.typeName.toString(),
467f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = entityColumnInput,
468f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = entity.fields.map { it.columnName }))
469092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
470092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
471092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
472092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val field = Field(
473092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                element = relationElement,
474092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                name = relationElement.simpleName.toString(),
475092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                type = context.processingEnv.typeUtils.asMemberOf(container, relationElement),
476092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                affinity = null,
477092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parent = parent)
478092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
4793ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        val projectionInput = AnnotationMirrors.getAnnotationValue(annotation, "projection")
480092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsStringList()
4813ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        val projection = if (projectionInput.isEmpty()) {
4823ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            // we need to infer the projection from inputs.
4833ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            createRelationshipProjection(inferEntity, typeArg, entity, entityField, typeArgElement)
4843ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        } else {
4853ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            // make sure projection makes sense
4863ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            validateRelationshipProjection(projectionInput, entity, relationElement)
4873ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            projectionInput
488092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
489092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // if types don't match, row adapter prints a warning
490ba069d50913c3fb250bb60ec310439db36895337Alan Viverette        return androidx.room.vo.Relation(
491092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entity = entity,
4923ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                pojoType = typeArg,
493092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                field = field,
494092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parentField = parentField,
495092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entityField = entityField,
496092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                projection = projection
497092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        )
498092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
499092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
5003ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar    private fun validateRelationshipProjection(
5013ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            projectionInput: List<String>,
5023ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            entity: Entity,
5033ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            relationElement: VariableElement) {
5043ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        val missingColumns = projectionInput.filterNot { columnName ->
5053ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            entity.fields.any { columnName == it.columnName }
5063ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        }
5073ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        if (missingColumns.isNotEmpty()) {
5083ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            context.logger.e(relationElement,
5093ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                    ProcessorErrors.relationBadProject(entity.typeName.toString(),
5103ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                            missingColumns, entity.fields.map { it.columnName }))
5113ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        }
5123ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar    }
5133ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar
5143ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar    /**
5153ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     * Create the projection column list based on the relationship args.
5163ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *
5173ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *  if entity field in the annotation is not specified, it is the method return type
5183ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *  if it is specified in the annotation:
5193ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *       still check the method return type, if the same, use it
5203ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *       if not, check to see if we can find a column Adapter, if so use the childField
5213ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     *       last resort, try to parse it as a pojo to infer it.
5223ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar     */
5233ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar    private fun createRelationshipProjection(
5243ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            inferEntity: Boolean,
5253ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            typeArg: TypeMirror,
5263ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            entity: Entity,
5273ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            entityField: Field,
5283ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            typeArgElement: TypeElement): List<String> {
5293ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        return if (inferEntity || typeArg.typeName() == entity.typeName) {
5303ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            entity.fields.map { it.columnName }
5313ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        } else {
5323ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            val columnAdapter = context.typeAdapterStore.findCursorValueReader(typeArg, null)
5333ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            if (columnAdapter != null) {
5343ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                // nice, there is a column adapter for this, assume single column response
5353ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                listOf(entityField.name)
5363ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            } else {
5373ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                // last resort, it needs to be a pojo
5383ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                val pojo = PojoProcessor(
5393ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                        baseContext = context,
5403ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                        element = typeArgElement,
5413ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                        bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
5423ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                        parent = parent,
5433ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                        referenceStack = referenceStack).process()
5443ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar                pojo.fields.map { it.columnName }
5453ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar            }
5463ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar        }
5473ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar    }
5483ea1d11500fdfe07866c1d6fcc970159d0f04f3aYigit Boyar
5491a74519922de68e007027d56aae9370ee21f31f9shepshapard    private fun detectReferenceRecursion(typeElement: TypeElement): Boolean {
5501a74519922de68e007027d56aae9370ee21f31f9shepshapard        if (referenceStack.contains(typeElement.qualifiedName)) {
5511a74519922de68e007027d56aae9370ee21f31f9shepshapard            context.logger.e(
5521a74519922de68e007027d56aae9370ee21f31f9shepshapard                    typeElement,
5531a74519922de68e007027d56aae9370ee21f31f9shepshapard                    ProcessorErrors
5541a74519922de68e007027d56aae9370ee21f31f9shepshapard                            .RECURSIVE_REFERENCE_DETECTED
5551a74519922de68e007027d56aae9370ee21f31f9shepshapard                            .format(computeReferenceRecursionString(typeElement)))
5561a74519922de68e007027d56aae9370ee21f31f9shepshapard            return true
5571a74519922de68e007027d56aae9370ee21f31f9shepshapard        }
5581a74519922de68e007027d56aae9370ee21f31f9shepshapard        return false
5591a74519922de68e007027d56aae9370ee21f31f9shepshapard    }
5601a74519922de68e007027d56aae9370ee21f31f9shepshapard
5611a74519922de68e007027d56aae9370ee21f31f9shepshapard    private fun computeReferenceRecursionString(typeElement: TypeElement): String {
5621a74519922de68e007027d56aae9370ee21f31f9shepshapard        val recursiveTailTypeName = typeElement.qualifiedName
5631a74519922de68e007027d56aae9370ee21f31f9shepshapard
5641a74519922de68e007027d56aae9370ee21f31f9shepshapard        val referenceRecursionList = mutableListOf<Name>()
5659e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        with(referenceRecursionList) {
5661a74519922de68e007027d56aae9370ee21f31f9shepshapard            add(recursiveTailTypeName)
5671a74519922de68e007027d56aae9370ee21f31f9shepshapard            addAll(referenceStack.toList().takeLastWhile { it != recursiveTailTypeName })
5681a74519922de68e007027d56aae9370ee21f31f9shepshapard            add(recursiveTailTypeName)
5691a74519922de68e007027d56aae9370ee21f31f9shepshapard        }
5701a74519922de68e007027d56aae9370ee21f31f9shepshapard
5711a74519922de68e007027d56aae9370ee21f31f9shepshapard        return referenceRecursionList.joinToString(" -> ")
5721a74519922de68e007027d56aae9370ee21f31f9shepshapard    }
5731a74519922de68e007027d56aae9370ee21f31f9shepshapard
574757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    private fun assignGetters(fields: List<Field>, getterCandidates: List<PojoMethod>) {
57513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
576092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(field, getterCandidates)
57713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
57813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
57913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
580757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    private fun assignGetter(field: Field, getterCandidates: List<PojoMethod>) {
581092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
582092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = getterCandidates,
583092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.getterNameWithVariations,
584092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
585757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    method.resolvedType.returnType
586092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
587092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
588092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
589092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
590092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
591092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
592092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
593092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
594092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
595757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            name = match.name,
596757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            type = match.resolvedType.returnType,
597092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
598092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
599092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
600092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
601092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingGetters(field, matching))
602092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
603092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
604092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
605092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
606757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    private fun assignSetters(
607757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            fields: List<Field>,
608757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            setterCandidates: List<PojoMethod>,
609757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            constructor: Constructor?) {
61013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
611f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(field, setterCandidates, constructor)
6125bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
6135bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
6145bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
615757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    private fun assignSetter(
616757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            field: Field,
617757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            setterCandidates: List<PojoMethod>,
618757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            constructor: Constructor?) {
619f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (constructor != null && constructor.hasField(field)) {
620f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR)
621f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return
622f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
623092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
624092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = setterCandidates,
625092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.setterNameWithVariations,
626092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
627757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    method.resolvedType.parameterTypes.first()
628092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
629092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
630092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
631092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
632092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
633092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
634092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
635092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
636757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    val paramType = match.resolvedType.parameterTypes.first()
637092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
638757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            name = match.name,
639092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = paramType,
640092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
641092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
642092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
643092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
644092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingSetter(field, matching))
645092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
646092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD)
647092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
648092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
6495bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    /**
6505bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * Finds a setter/getter from available list of methods.
6515bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * It returns true if assignment is successful, false otherwise.
6525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * At worst case, it sets to the field as if it is accessible so that the rest of the
6535bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * compilation can continue.
6545bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     */
655757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    private fun chooseAssignment(
656757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            field: Field,
657757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            candidates: List<PojoMethod>,
658757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            nameVariations: List<String>,
659757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            getType: (PojoMethod) -> TypeMirror,
660757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            assignFromField: () -> Unit,
661757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            assignFromMethod: (PojoMethod) -> Unit,
662757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            reportAmbiguity: (List<String>) -> Unit
663757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    ): Boolean {
6645bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (field.element.hasAnyOf(PUBLIC)) {
6655bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
6665bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
6675bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
6685bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val types = context.processingEnv.typeUtils
6696d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar
6705bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val matching = candidates
6715bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .filter {
6722fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar                    // b/69164099
673757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    types.isAssignableWithoutVariance(getType(it), field.type)
674757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            && (field.nameWithVariations.contains(it.name)
675757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                            || nameVariations.contains(it.name))
67613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
6775bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .groupBy {
678757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                    if (it.element.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED
6795bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                }
6805bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (matching.isEmpty()) {
6815bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // we always assign to avoid NPEs in the rest of the compilation.
6825bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
6835bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if field is not private, assume it works (if we are on the same package).
6845bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if not, compiler will tell, we didn't have any better alternative anyways.
6855bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return !field.element.hasAnyOf(PRIVATE)
6865bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
687757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar        val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity)
688757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar                ?: verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity)
6895bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (match == null) {
6905bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
6915bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return false
6925bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        } else {
6935bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromMethod(match)
6945bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
6955bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
6965bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
6975bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
6986f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private fun verifyAndChooseOneFrom(
699757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            candidates: List<PojoMethod>?,
7006f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            reportAmbiguity: (List<String>) -> Unit
701757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar    ): PojoMethod? {
7025bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates == null) {
7035bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return null
7045bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
7055bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates.size > 1) {
706757abd3002dff7725cde3cebdbf9bfeed691d2f9Yigit Boyar            reportAmbiguity(candidates.map { it.name })
70713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
7085bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        return candidates.first()
70913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
7109e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar
7119e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    private data class FailedConstructor(
7129e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val method: ExecutableElement,
7139e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val params: List<String>,
7149e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val matches: List<Constructor.Param?>
7159e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    ) {
7169e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        fun log(): String {
7179e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            val logPerParam = params.withIndex().joinToString(", ") {
7189e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar                "param:${it.value} -> matched field:" + (matches[it.index]?.log() ?: "unmatched")
7199e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            }
7209e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar            return "$method -> [$logPerParam]"
7219e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar        }
7229e828633846e3c3ff9738dbc567fe16c05e5d1b4Yigit Boyar    }
72313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar}
724