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
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room.processor
1813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
1964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Relation
2064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ColumnInfo
214d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyarimport android.arch.persistence.room.Embedded
2264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Ignore
2364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAllFieldsIncludingPrivateSupers
2464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAnnotationValue
2564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAsString
2664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAsStringList
2764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.hasAnnotation
2864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.hasAnyOf
2964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.isCollection
3064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.toClassType
3164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD
3264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD
3364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_TYPE
3464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME
3564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.cache.Cache
3664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.CallType
3764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Constructor
3864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Field
3964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.FieldGetter
404d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyarimport android.arch.persistence.room.vo.EmbeddedField
4164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Entity
4264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.FieldSetter
4364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Pojo
44092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport com.google.auto.common.AnnotationMirrors
4513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreElements
4613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreTypes
4796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.element.Element
4813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.ExecutableElement
4913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier
5013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.ABSTRACT
5113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.PRIVATE
525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PROTECTED
535bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PUBLIC
5413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.STATIC
55a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyarimport javax.lang.model.element.Modifier.TRANSIENT
5613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.TypeElement
57092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport javax.lang.model.element.VariableElement
5896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.type.DeclaredType
5913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.type.TypeKind
605bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.type.TypeMirror
61f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyarimport javax.lang.model.util.ElementFilter
6213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
6313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/**
6413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Processes any class as if it is a Pojo.
6513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */
6696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarclass PojoProcessor(baseContext: Context, val element: TypeElement,
6796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    val bindingScope: FieldProcessor.BindingScope,
684d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    val parent: EmbeddedField?) {
69aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar    val context = baseContext.fork(element)
70092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    companion object {
714d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class,
72092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    Relation::class)
73092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
745124503104860e68981cc3e3092b95932586f66fYigit Boyar    fun process() : Pojo {
755124503104860e68981cc3e3092b95932586f66fYigit Boyar        return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), {
765124503104860e68981cc3e3092b95932586f66fYigit Boyar            doProcess()
775124503104860e68981cc3e3092b95932586f66fYigit Boyar        })
785124503104860e68981cc3e3092b95932586f66fYigit Boyar    }
795124503104860e68981cc3e3092b95932586f66fYigit Boyar
805124503104860e68981cc3e3092b95932586f66fYigit Boyar    private fun doProcess(): Pojo {
81092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // TODO handle recursion: b/35980205
8213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val declaredType = MoreTypes.asDeclared(element.asType())
8396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        // TODO handle conflicts with super: b/35568142
8496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val allFields = element.getAllFieldsIncludingPrivateSupers(context.processingEnv)
8513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
86a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                    !it.hasAnnotation(Ignore::class)
87a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                            && !it.hasAnyOf(STATIC)
88a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                            && (!it.hasAnyOf(TRANSIENT)
89a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                                    || it.hasAnnotation(ColumnInfo::class)
90a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                                    || it.hasAnnotation(Embedded::class)
91a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar                                    || it.hasAnnotation(Relation::class))
9296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
93092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .groupBy { field ->
94092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.checker.check(
95092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            PROCESSED_ANNOTATIONS.count { field.hasAnnotation(it) } < 2, field,
96092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION
97092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    )
984d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    if (field.hasAnnotation(Embedded::class)) {
994d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Embedded::class
100092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else if (field.hasAnnotation(Relation::class)) {
101092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        Relation::class
102092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else {
103092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        null
104092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    }
105092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
106092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myFields = allFields[null]
107092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
10896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    FieldProcessor(
10996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            baseContext = context,
11096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            containing = declaredType,
11196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            element = it,
11296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            bindingScope = bindingScope,
11396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            fieldParent = parent).process()
114092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                } ?: emptyList()
115092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1164d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedFields = allFields[Embedded::class]
117092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
1184d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    processEmbeddedField(declaredType, it)
119092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                } ?: emptyList()
1204d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subFields = embeddedFields.flatMap { it.pojo.fields }
12113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
12296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val fields = myFields + subFields
123092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
124092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myRelationsList = allFields[Relation::class]
125092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
126092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    processRelationField(fields, declaredType, it)
127092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
128092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.filterNotNull() ?: emptyList()
129092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1304d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subRelations = embeddedFields.flatMap { it.pojo.relations }
131092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
132092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val relations = myRelationsList + subRelations
133092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
13496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        fields.groupBy { it.columnName }
13596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .filter { it.value.size > 1 }
13696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .forEach {
13796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    context.logger.e(element, ProcessorErrors.pojoDuplicateFieldNames(
13896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            it.key, it.value.map(Field::getPath)
13996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    ))
14096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    it.value.forEach {
14196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        context.logger.e(it.element, POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME)
14296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    }
14396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
14496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val methods = MoreElements.getLocalAndInheritedMethods(element,
14596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                context.processingEnv.elementUtils)
14613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
14796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC)
14813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                            && !it.hasAnnotation(Ignore::class)
14913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
15013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .map { MoreElements.asExecutable(it) }
15113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
15213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val getterCandidates = methods.filter {
15313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            it.parameters.size == 0 && it.returnType.kind != TypeKind.VOID
15413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
15513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
15613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val setterCandidates = methods.filter {
15713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            it.parameters.size == 1 && it.returnType.kind == TypeKind.VOID
15813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
159f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        // don't try to find a constructor for binding to statement.
160f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructor = if (bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT) {
161f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            // we don't need to construct this POJO.
162f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            null
163f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        } else {
1644d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar            chooseConstructor(myFields, embeddedFields)
165f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
16613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
16796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        assignGetters(myFields, getterCandidates)
168f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        assignSetters(myFields, setterCandidates, constructor)
169092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1704d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        embeddedFields.forEach {
171092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
172f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
173092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
174092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
175092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        myRelationsList.forEach {
176092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
177f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
178092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
179092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
18096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val pojo = Pojo(element = element,
18196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                type = declaredType,
18296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                fields = fields,
1834d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                embeddedFields = embeddedFields,
184f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                relations = relations,
185f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                constructor = constructor)
18613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        return pojo
18713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
18813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
1894d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar    private fun chooseConstructor(myFields: List<Field>, embedded: List<EmbeddedField>)
190f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            : Constructor? {
191f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructors = ElementFilter.constructorsIn(element.enclosedElements)
192f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                .filterNot { it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE) }
193f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val fieldMap = myFields.associateBy { it.name }
1944d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedMap = embedded.associateBy { it.field.name }
195f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val typeUtils = context.processingEnv.typeUtils
196f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val failedConstructors = mutableMapOf<ExecutableElement, List<Constructor.Param?>>()
197f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val goodConstructors = constructors.map { constructor ->
198f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            val params = constructor.parameters.map param@ { param ->
199f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val paramName = param.simpleName.toString()
200f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val paramType = param.asType()
201f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
202f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matches = fun(field: Field?): Boolean {
203f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return if (field == null) {
204f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
205f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else if (!field.nameWithVariations.contains(paramName)) {
206f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
207f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
208f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        typeUtils.isAssignable(paramType, field.type)
209f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
210f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
211f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
212f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val exactFieldMatch = fieldMap[paramName]
213f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
214f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                if (matches(exactFieldMatch)) {
215f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return@param Constructor.FieldParam(exactFieldMatch!!)
216f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2174d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val exactEmbeddedMatch = embeddedMap[paramName]
2184d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matches(exactEmbeddedMatch?.field)) {
2194d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    return@param Constructor.EmbeddedParam(exactEmbeddedMatch!!)
220f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
221f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
222f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matchingFields = myFields.filter {
223f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it)
224f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2254d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val embeddedMatches = embedded.filter {
226f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it.field)
227f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2284d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matchingFields.isEmpty() && embeddedMatches.isEmpty()) {
229f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
2304d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                } else if (matchingFields.size + embeddedMatches.size == 1) {
231f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    if (matchingFields.isNotEmpty()) {
232f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        Constructor.FieldParam(matchingFields.first())
233f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
2344d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Constructor.EmbeddedParam(embeddedMatches.first())
235f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
236f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                } else {
237f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    context.logger.e(param, ProcessorErrors.ambigiousConstructor(
238f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            pojo = element.qualifiedName.toString(),
239f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            paramName = param.simpleName.toString(),
240f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            matchingFields = matchingFields.map { it.getPath() }
2414d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                                    + embedded.map { it.field.getPath() }
242f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    ))
243f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
244f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
245f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
246f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            if (params.any { it == null }) {
247f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                failedConstructors.put(constructor, params)
248f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                null
249f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            } else {
250f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                @Suppress("UNCHECKED_CAST")
251f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                Constructor(constructor, params as List<Constructor.Param>)
252f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
253f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }.filterNotNull()
254f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (goodConstructors.isEmpty()) {
255f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            if (failedConstructors.isNotEmpty()) {
256f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val failureMsg = failedConstructors.entries.joinToString("\n") { entry ->
257f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    val paramsMatching = entry.key.parameters.withIndex().joinToString(", ") {
258f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        "${it.value.simpleName} : ${entry.value[it.index]?.log()}"
259f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
260f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    "${entry.key} : [$paramsMatching]"
261f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
262f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR +
263f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        "\nTried the following constructors but they failed to match:\n$failureMsg")
264f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
265f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
266f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return null
267f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
268f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (goodConstructors.size > 1) {
269f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            goodConstructors.forEach {
270f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
271f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
272f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return null
273f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
274f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        return goodConstructors.first()
275f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    }
276f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
2774d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar    private fun processEmbeddedField(declaredType: DeclaredType?, it: Element): EmbeddedField {
2784d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val fieldPrefix = it.getAnnotationValue(Embedded::class.java, "prefix")
27996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                ?.toString() ?: ""
28096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val inheritedPrefix = parent?.prefix ?: ""
2814d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedField = Field(
28296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                it,
28396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                it.simpleName.toString(),
28496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                type = context.processingEnv.typeUtils.asMemberOf(declaredType, it),
28596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                affinity = null,
2862c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                parent = parent)
2874d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subParent = EmbeddedField(
2884d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                field = embeddedField,
28996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                prefix = inheritedPrefix + fieldPrefix,
29096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                parent = parent)
29196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val asVariable = MoreElements.asVariable(it)
29296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        subParent.pojo = PojoProcessor(baseContext = context.fork(it),
29396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                element = MoreTypes.asTypeElement(asVariable.asType()),
29496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                bindingScope = bindingScope,
29596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                parent = subParent).process()
29696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        return subParent
29796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    }
29896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
299092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    private fun processRelationField(myFields : List<Field>, container: DeclaredType?,
300092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                     relationElement: VariableElement)
30164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar            : android.arch.persistence.room.vo.Relation? {
302092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val annotation = MoreElements.getAnnotationMirror(relationElement, Relation::class.java)
303092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .orNull()!!
304f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val parentColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "parentColumn")
305092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString("") ?: ""
306092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
307092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val parentField = myFields.firstOrNull {
308f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == parentColumnInput
309092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
310092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (parentField == null) {
311092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
312092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindParentEntityField(
313092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = element.qualifiedName.toString(),
314f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = parentColumnInput,
315f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = myFields.map { it.columnName }))
316092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
317092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
318092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // parse it as an entity.
319092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val asMember = MoreTypes
320092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .asMemberOf(context.processingEnv.typeUtils, container, relationElement)
321092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (asMember.kind == TypeKind.ERROR) {
322092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(ProcessorErrors.CANNOT_FIND_TYPE, element)
323092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
324092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
325092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val declared = MoreTypes.asDeclared(asMember)
326092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (!declared.isCollection()) {
327092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement, ProcessorErrors.RELATION_NOT_COLLECTION)
328092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
329092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
330092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val typeArg = declared.typeArguments.first()
331092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (typeArg.kind == TypeKind.ERROR) {
332092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(MoreTypes.asTypeElement(typeArg), CANNOT_FIND_TYPE)
333092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
334092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
335092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val typeArgElement = MoreTypes.asTypeElement(typeArg)
336092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityClassInput = AnnotationMirrors
337092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAnnotationValue(annotation, "entity").toClassType()
338092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val pojo : Pojo
339092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entity : Entity
340092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (entityClassInput == null
341092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                || MoreTypes.isTypeOf(Any::class.java, entityClassInput)) {
342092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            entity = EntityProcessor(context, typeArgElement).process()
343092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            pojo = entity
344092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        } else {
345092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            entity = EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput)).process()
346092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            pojo = PojoProcessor(baseContext = context,
347092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    element = typeArgElement,
348092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
349092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    parent = parent).process()
350092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
351092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // now find the field in the entity.
352f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val entityColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "entityColumn")
353092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString() ?: ""
354092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityField = entity.fields.firstOrNull {
355f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == entityColumnInput
356092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
357092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
358092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (entityField == null) {
359092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
360092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindEntityField(
361092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = entity.typeName.toString(),
362f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = entityColumnInput,
363f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = entity.fields.map { it.columnName }))
364092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
365092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
366092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
367092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val field = Field(
368092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                element = relationElement,
369092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                name = relationElement.simpleName.toString(),
370092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                type = context.processingEnv.typeUtils.asMemberOf(container, relationElement),
371092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                affinity = null,
372092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parent = parent)
373092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
374092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val projection = AnnotationMirrors.getAnnotationValue(annotation, "projection")
375092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsStringList()
376092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if(projection.isNotEmpty()) {
377092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            val missingColumns = projection.filterNot { columnName ->
378092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entity.fields.any { columnName == it.columnName }
379092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            }
380092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            if (missingColumns.isNotEmpty()) {
381092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                context.logger.e(relationElement,
382092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        ProcessorErrors.relationBadProject(entity.typeName.toString(),
383092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                missingColumns, entity.fields.map { it.columnName }))
384092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            }
385092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
386092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
387092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // if types don't match, row adapter prints a warning
38864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar        return android.arch.persistence.room.vo.Relation(
389092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entity = entity,
390092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                pojo = pojo,
391092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                field = field,
392092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parentField = parentField,
393092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entityField = entityField,
394092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                projection = projection
395092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        )
396092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
397092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
39813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) {
39913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
400092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(field, getterCandidates)
40113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
40213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
40313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
404092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    private fun assignGetter(field: Field, getterCandidates: List<ExecutableElement>) {
405092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
406092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = getterCandidates,
407092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.getterNameWithVariations,
408092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
409092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    method.returnType
410092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
411092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
412092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
413092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
414092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
415092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
416092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
417092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
418092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
419092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = match.simpleName.toString(),
420092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = match.returnType,
421092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
422092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
423092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
424092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
425092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingGetters(field, matching))
426092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
427092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
428092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
429092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
430f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>,
431f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                              constructor : Constructor?) {
43213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
433f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(field, setterCandidates, constructor)
4345bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
4355bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
4365bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
437f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    private fun assignSetter(field: Field, setterCandidates: List<ExecutableElement>,
438f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                             constructor: Constructor?) {
439f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (constructor != null && constructor.hasField(field)) {
440f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR)
441f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return
442f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
443092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
444092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = setterCandidates,
445092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.setterNameWithVariations,
446092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
447092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    method.parameters.first().asType()
448092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
449092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
450092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
451092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
452092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
453092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
454092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
455092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
456092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    val paramType = match.parameters.first().asType()
457092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
458092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = match.simpleName.toString(),
459092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = paramType,
460092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
461092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
462092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
463092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
464092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingSetter(field, matching))
465092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
466092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD)
467092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
468092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
4695bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    /**
4705bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * Finds a setter/getter from available list of methods.
4715bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * It returns true if assignment is successful, false otherwise.
4725bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * At worst case, it sets to the field as if it is accessible so that the rest of the
4735bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * compilation can continue.
4745bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     */
4755bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    private fun chooseAssignment(field: Field, candidates: List<ExecutableElement>,
47696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                                 nameVariations: List<String>,
47796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                                 getType: (ExecutableElement) -> TypeMirror,
4785bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 assignFromField: () -> Unit,
4795bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 assignFromMethod: (ExecutableElement) -> Unit,
4805bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 reportAmbiguity: (List<String>) -> Unit): Boolean {
4815bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (field.element.hasAnyOf(PUBLIC)) {
4825bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
4835bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
4845bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
4855bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val types = context.processingEnv.typeUtils
4866d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar
4875bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val matching = candidates
4885bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .filter {
4896d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar                    types.isAssignable(getType(it), field.element.asType())
4906d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar                            && (field.nameWithVariations.contains(it.simpleName.toString())
4916d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar                            || nameVariations.contains(it.simpleName.toString()))
49213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
4935bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .groupBy {
4945bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                    if (it.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED
4955bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                }
4965bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (matching.isEmpty()) {
4975bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // we always assign to avoid NPEs in the rest of the compilation.
4985bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
4995bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if field is not private, assume it works (if we are on the same package).
5005bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if not, compiler will tell, we didn't have any better alternative anyways.
5015bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return !field.element.hasAnyOf(PRIVATE)
5025bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
5035bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity) ?:
5045bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity)
5055bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (match == null) {
5065bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
5075bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return false
5085bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        } else {
5095bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromMethod(match)
5105bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
5115bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
5125bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
5135bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
5145bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    private fun verifyAndChooseOneFrom(candidates: List<ExecutableElement>?,
5155bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                       reportAmbiguity: (List<String>) -> Unit)
5165bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            : ExecutableElement? {
5175bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates == null) {
5185bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return null
5195bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
5205bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates.size > 1) {
5215bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            reportAmbiguity(candidates.map { it.simpleName.toString() })
52213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
5235bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        return candidates.first()
52413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
52513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar}
526