PojoProcessor.kt revision 4d4bae3f216e55f824d7d7fbfe2f8861906ee3e2
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
5513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.TypeElement
56092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport javax.lang.model.element.VariableElement
5796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.type.DeclaredType
5813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.type.TypeKind
595bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.type.TypeMirror
60f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyarimport javax.lang.model.util.ElementFilter
6113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
6213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/**
6313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Processes any class as if it is a Pojo.
6413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */
6596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarclass PojoProcessor(baseContext: Context, val element: TypeElement,
6696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    val bindingScope: FieldProcessor.BindingScope,
674d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    val parent: EmbeddedField?) {
68aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar    val context = baseContext.fork(element)
69092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    companion object {
704d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class,
71092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    Relation::class)
72092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
735124503104860e68981cc3e3092b95932586f66fYigit Boyar    fun process() : Pojo {
745124503104860e68981cc3e3092b95932586f66fYigit Boyar        return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), {
755124503104860e68981cc3e3092b95932586f66fYigit Boyar            doProcess()
765124503104860e68981cc3e3092b95932586f66fYigit Boyar        })
775124503104860e68981cc3e3092b95932586f66fYigit Boyar    }
785124503104860e68981cc3e3092b95932586f66fYigit Boyar
795124503104860e68981cc3e3092b95932586f66fYigit Boyar    private fun doProcess(): Pojo {
80092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // TODO handle recursion: b/35980205
8113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val declaredType = MoreTypes.asDeclared(element.asType())
8296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        // TODO handle conflicts with super: b/35568142
8396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val allFields = element.getAllFieldsIncludingPrivateSupers(context.processingEnv)
8413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
8596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    !it.hasAnnotation(Ignore::class) && !it.hasAnyOf(Modifier.STATIC)
8696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
87092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .groupBy { field ->
88092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.checker.check(
89092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            PROCESSED_ANNOTATIONS.count { field.hasAnnotation(it) } < 2, field,
90092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION
91092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    )
924d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    if (field.hasAnnotation(Embedded::class)) {
934d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Embedded::class
94092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else if (field.hasAnnotation(Relation::class)) {
95092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        Relation::class
96092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    } else {
97092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        null
98092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    }
99092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
100092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myFields = allFields[null]
101092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
10296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    FieldProcessor(
10396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            baseContext = context,
10496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            containing = declaredType,
10596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            element = it,
10696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            bindingScope = bindingScope,
10796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            fieldParent = parent).process()
108092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                } ?: emptyList()
109092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1104d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedFields = allFields[Embedded::class]
111092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
1124d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    processEmbeddedField(declaredType, it)
113092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                } ?: emptyList()
1144d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subFields = embeddedFields.flatMap { it.pojo.fields }
11513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
11696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val fields = myFields + subFields
117092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
118092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val myRelationsList = allFields[Relation::class]
119092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.map {
120092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    processRelationField(fields, declaredType, it)
121092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                }
122092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                ?.filterNotNull() ?: emptyList()
123092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1244d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subRelations = embeddedFields.flatMap { it.pojo.relations }
125092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
126092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val relations = myRelationsList + subRelations
127092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
12896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        fields.groupBy { it.columnName }
12996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .filter { it.value.size > 1 }
13096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                .forEach {
13196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    context.logger.e(element, ProcessorErrors.pojoDuplicateFieldNames(
13296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                            it.key, it.value.map(Field::getPath)
13396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    ))
13496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    it.value.forEach {
13596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        context.logger.e(it.element, POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME)
13696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    }
13796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                }
13896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val methods = MoreElements.getLocalAndInheritedMethods(element,
13996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                context.processingEnv.elementUtils)
14013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .filter {
14196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                    !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC)
14213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                            && !it.hasAnnotation(Ignore::class)
14313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
14413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                .map { MoreElements.asExecutable(it) }
14513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
14613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val getterCandidates = methods.filter {
14713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            it.parameters.size == 0 && it.returnType.kind != TypeKind.VOID
14813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
14913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
15013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        val setterCandidates = methods.filter {
15113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            it.parameters.size == 1 && it.returnType.kind == TypeKind.VOID
15213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
153f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        // don't try to find a constructor for binding to statement.
154f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructor = if (bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT) {
155f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            // we don't need to construct this POJO.
156f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            null
157f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        } else {
1584d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar            chooseConstructor(myFields, embeddedFields)
159f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
16013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
16196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        assignGetters(myFields, getterCandidates)
162f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        assignSetters(myFields, setterCandidates, constructor)
163092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
1644d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        embeddedFields.forEach {
165092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
166f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
167092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
168092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
169092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        myRelationsList.forEach {
170092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(it.field, getterCandidates)
171f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(it.field, setterCandidates, constructor)
172092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
173092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
17496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val pojo = Pojo(element = element,
17596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                type = declaredType,
17696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                fields = fields,
1774d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                embeddedFields = embeddedFields,
178f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                relations = relations,
179f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                constructor = constructor)
18013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        return pojo
18113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
18213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
1834d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar    private fun chooseConstructor(myFields: List<Field>, embedded: List<EmbeddedField>)
184f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            : Constructor? {
185f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val constructors = ElementFilter.constructorsIn(element.enclosedElements)
186f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                .filterNot { it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE) }
187f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val fieldMap = myFields.associateBy { it.name }
1884d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedMap = embedded.associateBy { it.field.name }
189f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val typeUtils = context.processingEnv.typeUtils
190f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val failedConstructors = mutableMapOf<ExecutableElement, List<Constructor.Param?>>()
191f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        val goodConstructors = constructors.map { constructor ->
192f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            val params = constructor.parameters.map param@ { param ->
193f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val paramName = param.simpleName.toString()
194f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val paramType = param.asType()
195f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
196f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matches = fun(field: Field?): Boolean {
197f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return if (field == null) {
198f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
199f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else if (!field.nameWithVariations.contains(paramName)) {
200f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        false
201f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
202f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        typeUtils.isAssignable(paramType, field.type)
203f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
204f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
205f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
206f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val exactFieldMatch = fieldMap[paramName]
207f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
208f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                if (matches(exactFieldMatch)) {
209f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    return@param Constructor.FieldParam(exactFieldMatch!!)
210f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2114d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val exactEmbeddedMatch = embeddedMap[paramName]
2124d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matches(exactEmbeddedMatch?.field)) {
2134d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                    return@param Constructor.EmbeddedParam(exactEmbeddedMatch!!)
214f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
215f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
216f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val matchingFields = myFields.filter {
217f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it)
218f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2194d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                val embeddedMatches = embedded.filter {
220f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    matches(it.field)
221f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
2224d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                if (matchingFields.isEmpty() && embeddedMatches.isEmpty()) {
223f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
2244d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                } else if (matchingFields.size + embeddedMatches.size == 1) {
225f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    if (matchingFields.isNotEmpty()) {
226f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        Constructor.FieldParam(matchingFields.first())
227f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    } else {
2284d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                        Constructor.EmbeddedParam(embeddedMatches.first())
229f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
230f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                } else {
231f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    context.logger.e(param, ProcessorErrors.ambigiousConstructor(
232f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            pojo = element.qualifiedName.toString(),
233f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            paramName = param.simpleName.toString(),
234f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                            matchingFields = matchingFields.map { it.getPath() }
2354d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                                    + embedded.map { it.field.getPath() }
236f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    ))
237f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    null
238f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
239f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
240f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            if (params.any { it == null }) {
241f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                failedConstructors.put(constructor, params)
242f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                null
243f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            } else {
244f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                @Suppress("UNCHECKED_CAST")
245f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                Constructor(constructor, params as List<Constructor.Param>)
246f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
247f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }.filterNotNull()
248f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (goodConstructors.isEmpty()) {
249f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            if (failedConstructors.isNotEmpty()) {
250f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val failureMsg = failedConstructors.entries.joinToString("\n") { entry ->
251f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    val paramsMatching = entry.key.parameters.withIndex().joinToString(", ") {
252f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        "${it.value.simpleName} : ${entry.value[it.index]?.log()}"
253f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    }
254f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                    "${entry.key} : [$paramsMatching]"
255f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                }
256f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR +
257f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                        "\nTried the following constructors but they failed to match:\n$failureMsg")
258f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
259f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
260f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return null
261f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
262f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (goodConstructors.size > 1) {
263f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            goodConstructors.forEach {
264f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
265f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            }
266f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return null
267f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
268f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        return goodConstructors.first()
269f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    }
270f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar
2714d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar    private fun processEmbeddedField(declaredType: DeclaredType?, it: Element): EmbeddedField {
2724d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val fieldPrefix = it.getAnnotationValue(Embedded::class.java, "prefix")
27396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                ?.toString() ?: ""
27496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val inheritedPrefix = parent?.prefix ?: ""
2754d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val embeddedField = Field(
27696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                it,
27796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                it.simpleName.toString(),
27896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                type = context.processingEnv.typeUtils.asMemberOf(declaredType, it),
27996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                affinity = null,
2802c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                parent = parent)
2814d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar        val subParent = EmbeddedField(
2824d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar                field = embeddedField,
28396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                prefix = inheritedPrefix + fieldPrefix,
28496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                parent = parent)
28596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        val asVariable = MoreElements.asVariable(it)
28696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        subParent.pojo = PojoProcessor(baseContext = context.fork(it),
28796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                element = MoreTypes.asTypeElement(asVariable.asType()),
28896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                bindingScope = bindingScope,
28996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                parent = subParent).process()
29096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        return subParent
29196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    }
29296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
293092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    private fun processRelationField(myFields : List<Field>, container: DeclaredType?,
294092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                     relationElement: VariableElement)
29564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar            : android.arch.persistence.room.vo.Relation? {
296092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val annotation = MoreElements.getAnnotationMirror(relationElement, Relation::class.java)
297092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .orNull()!!
298f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val parentColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "parentColumn")
299092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString("") ?: ""
300092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
301092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val parentField = myFields.firstOrNull {
302f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == parentColumnInput
303092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
304092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (parentField == null) {
305092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
306092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindParentEntityField(
307092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = element.qualifiedName.toString(),
308f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = parentColumnInput,
309f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = myFields.map { it.columnName }))
310092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
311092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
312092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // parse it as an entity.
313092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val asMember = MoreTypes
314092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .asMemberOf(context.processingEnv.typeUtils, container, relationElement)
315092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (asMember.kind == TypeKind.ERROR) {
316092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(ProcessorErrors.CANNOT_FIND_TYPE, element)
317092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
318092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
319092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val declared = MoreTypes.asDeclared(asMember)
320092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (!declared.isCollection()) {
321092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement, ProcessorErrors.RELATION_NOT_COLLECTION)
322092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
323092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
324092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val typeArg = declared.typeArguments.first()
325092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (typeArg.kind == TypeKind.ERROR) {
326092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(MoreTypes.asTypeElement(typeArg), CANNOT_FIND_TYPE)
327092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
328092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
329092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val typeArgElement = MoreTypes.asTypeElement(typeArg)
330092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityClassInput = AnnotationMirrors
331092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAnnotationValue(annotation, "entity").toClassType()
332092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val pojo : Pojo
333092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entity : Entity
334092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (entityClassInput == null
335092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                || MoreTypes.isTypeOf(Any::class.java, entityClassInput)) {
336092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            entity = EntityProcessor(context, typeArgElement).process()
337092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            pojo = entity
338092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        } else {
339092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            entity = EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput)).process()
340092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            pojo = PojoProcessor(baseContext = context,
341092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    element = typeArgElement,
342092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
343092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    parent = parent).process()
344092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
345092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // now find the field in the entity.
346f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        val entityColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "entityColumn")
347092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsString() ?: ""
348092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val entityField = entity.fields.firstOrNull {
349f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar            it.columnName == entityColumnInput
350092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
351092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
352092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if (entityField == null) {
353092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            context.logger.e(relationElement,
354092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    ProcessorErrors.relationCannotFindEntityField(
355092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            entityName = entity.typeName.toString(),
356f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            columnName = entityColumnInput,
357f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                            availableColumns = entity.fields.map { it.columnName }))
358092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            return null
359092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
360092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
361092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val field = Field(
362092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                element = relationElement,
363092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                name = relationElement.simpleName.toString(),
364092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                type = context.processingEnv.typeUtils.asMemberOf(container, relationElement),
365092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                affinity = null,
366092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parent = parent)
367092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
368092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val projection = AnnotationMirrors.getAnnotationValue(annotation, "projection")
369092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                .getAsStringList()
370092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        if(projection.isNotEmpty()) {
371092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            val missingColumns = projection.filterNot { columnName ->
372092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entity.fields.any { columnName == it.columnName }
373092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            }
374092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            if (missingColumns.isNotEmpty()) {
375092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                context.logger.e(relationElement,
376092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                        ProcessorErrors.relationBadProject(entity.typeName.toString(),
377092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                missingColumns, entity.fields.map { it.columnName }))
378092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            }
379092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        }
380092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
381092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        // if types don't match, row adapter prints a warning
38264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar        return android.arch.persistence.room.vo.Relation(
383092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entity = entity,
384092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                pojo = pojo,
385092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                field = field,
386092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                parentField = parentField,
387092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                entityField = entityField,
388092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                projection = projection
389092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        )
390092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
391092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
39213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) {
39313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
394092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            assignGetter(field, getterCandidates)
39513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
39613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
39713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
398092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    private fun assignGetter(field: Field, getterCandidates: List<ExecutableElement>) {
399092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
400092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = getterCandidates,
401092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.getterNameWithVariations,
402092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
403092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    method.returnType
404092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
405092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
406092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
407092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
408092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
409092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
410092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
411092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
412092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.getter = FieldGetter(
413092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = match.simpleName.toString(),
414092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = match.returnType,
415092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
416092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
417092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
418092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
419092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingGetters(field, matching))
420092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
421092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
422092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
423092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
424f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>,
425f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                              constructor : Constructor?) {
42613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        fields.forEach { field ->
427f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            assignSetter(field, setterCandidates, constructor)
4285bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
4295bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
4305bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
431f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar    private fun assignSetter(field: Field, setterCandidates: List<ExecutableElement>,
432f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                             constructor: Constructor?) {
433f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        if (constructor != null && constructor.hasField(field)) {
434f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR)
435f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar            return
436f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        }
437092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val success = chooseAssignment(field = field,
438092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                candidates = setterCandidates,
439092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                nameVariations = field.setterNameWithVariations,
440092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                getType = { method ->
441092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    method.parameters.first().asType()
442092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
443092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromField = {
444092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
445092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = field.name,
446092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = field.type,
447092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.FIELD)
448092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
449092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                assignFromMethod = { match ->
450092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    val paramType = match.parameters.first().asType()
451092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    field.setter = FieldSetter(
452092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            name = match.simpleName.toString(),
453092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            type = paramType,
454092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            callType = CallType.METHOD)
455092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                },
456092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                reportAmbiguity = { matching ->
457092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                    context.logger.e(field.element,
458092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                            ProcessorErrors.tooManyMatchingSetter(field, matching))
459092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                })
460092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD)
461092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
462092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
4635bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    /**
4645bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * Finds a setter/getter from available list of methods.
4655bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * It returns true if assignment is successful, false otherwise.
4665bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * At worst case, it sets to the field as if it is accessible so that the rest of the
4675bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     * compilation can continue.
4685bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar     */
4695bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    private fun chooseAssignment(field: Field, candidates: List<ExecutableElement>,
47096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                                 nameVariations: List<String>,
47196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                                 getType: (ExecutableElement) -> TypeMirror,
4725bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 assignFromField: () -> Unit,
4735bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 assignFromMethod: (ExecutableElement) -> Unit,
4745bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                 reportAmbiguity: (List<String>) -> Unit): Boolean {
4755bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (field.element.hasAnyOf(PUBLIC)) {
4765bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
4775bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
4785bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
4795bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val types = context.processingEnv.typeUtils
4805bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val matching = candidates
4815bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .filter {
4825bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                    types.isSameType(field.element.asType(), getType(it))
4835bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                            && field.nameWithVariations.contains(it.simpleName.toString())
4845bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                            || nameVariations.contains(it.simpleName.toString())
48513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                }
4865bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                .groupBy {
4875bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                    if (it.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED
4885bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                }
4895bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (matching.isEmpty()) {
4905bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // we always assign to avoid NPEs in the rest of the compilation.
4915bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
4925bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if field is not private, assume it works (if we are on the same package).
4935bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            // if not, compiler will tell, we didn't have any better alternative anyways.
4945bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return !field.element.hasAnyOf(PRIVATE)
4955bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
4965bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity) ?:
4975bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity)
4985bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (match == null) {
4995bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromField()
5005bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return false
5015bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        } else {
5025bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            assignFromMethod(match)
5035bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return true
5045bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
5055bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    }
5065bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar
5075bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar    private fun verifyAndChooseOneFrom(candidates: List<ExecutableElement>?,
5085bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar                                       reportAmbiguity: (List<String>) -> Unit)
5095bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            : ExecutableElement? {
5105bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates == null) {
5115bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            return null
5125bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        }
5135bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        if (candidates.size > 1) {
5145bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar            reportAmbiguity(candidates.map { it.simpleName.toString() })
51513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
5165bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar        return candidates.first()
51713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
51813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar}
519