@@ -28,10 +28,12 @@ import com.squareup.anvil.compiler.internal.asClassName
28
28
import com.squareup.anvil.compiler.internal.buildFile
29
29
import com.squareup.anvil.compiler.internal.fqName
30
30
import com.squareup.anvil.compiler.internal.reference.*
31
+ import com.squareup.anvil.compiler.internal.reference.ClassReference.Psi
31
32
import com.squareup.kotlinpoet.*
32
33
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
33
34
import dagger.BindsOptionalOf
34
35
import dagger.Provides
36
+ import dagger.multibindings.IntoSet
35
37
import java.io.File
36
38
import javax.inject.Inject
37
39
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -169,6 +171,36 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
169
171
.build(),
170
172
)
171
173
}
174
+ addFunction(
175
+ FunSpec .builder(" provides${boundType.shortName} Inventory" )
176
+ .addAnnotation(Provides ::class .asClassName())
177
+ .addAnnotation(
178
+ AnnotationSpec .builder(singleInstanceAnnotationFqName.asClassName(module))
179
+ .addMember(" scope = %T::class" , scope.asClassName())
180
+ .build(),
181
+ )
182
+ .addAnnotation(IntoSet ::class .asClassName())
183
+ .addParameter(" feature" , boundType.asClassName())
184
+ .addCode(
185
+ CodeBlock .of(
186
+ """
187
+ return object : FeatureTogglesInventory {
188
+ override suspend fun getAll(): List<Toggle> {
189
+ return feature.javaClass.declaredMethods.mapNotNull { method ->
190
+ if (method.genericReturnType.toString().contains(Toggle::class.java.canonicalName!!)) {
191
+ method.invoke(feature) as Toggle
192
+ } else {
193
+ null
194
+ }
195
+ }
196
+ }
197
+ }
198
+ """ .trimIndent(),
199
+ ),
200
+ )
201
+ .returns(FeatureTogglesInventory ::class .asClassName())
202
+ .build(),
203
+ )
172
204
}
173
205
.build(),
174
206
)
@@ -871,6 +903,31 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
871
903
vmClass : ClassReference .Psi ,
872
904
module : ModuleDescriptor ,
873
905
): CustomStorePresence {
906
+ fun requireFeatureAndStoreCrossReference (vmClass : Psi , storeClass : ClassReference ) {
907
+ // check if the store is annotated with RemoteFeatureStoreNamed
908
+ if (storeClass.annotations.none { it.fqName == RemoteFeatureStoreNamed ::class .fqName }) {
909
+ throw AnvilCompilationException (
910
+ " ${storeClass.fqName} shall be annotated with [RemoteFeatureStoreNamed]" ,
911
+ element = vmClass.clazz.identifyingElement,
912
+ )
913
+ } else {
914
+ // lastly, check that both the feature and store reference each other
915
+ val storedDefineFeature = storeClass.annotations
916
+ .first { it.fqName == RemoteFeatureStoreNamed ::class .fqName }
917
+ .remoteFeatureStoreValueOrNull()
918
+
919
+ // check the boundType to ensure triggers work as expected
920
+ val annotation = vmClass.annotations.first { it.fqName == ContributesRemoteFeature ::class .fqName }
921
+ val featureClass = annotation.boundTypeOrNull() ? : vmClass
922
+ if (storedDefineFeature?.fqName != featureClass.fqName) {
923
+ throw AnvilCompilationException (
924
+ " ${vmClass.fqName} and ${featureClass.fqName} don't reference each other" ,
925
+ element = vmClass.clazz.identifyingElement,
926
+ )
927
+ }
928
+ }
929
+ }
930
+
874
931
var exceptionStore = false
875
932
var settingsStore = false
876
933
var toggleStore = false
@@ -912,33 +969,44 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
912
969
}
913
970
with (annotation.settingsStoreOrNull()) {
914
971
settingsStore = this != null
915
- if (this != null && this .directSuperTypeReferences()
916
- .none { it.asClassReferenceOrNull()?.fqName == FeatureSettings .Store ::class .fqName }
917
- ) {
918
- throw AnvilCompilationException (
919
- " ${vmClass.fqName} [settingsStore] must extend [FeatureSettings.Store]" ,
920
- element = vmClass.clazz.identifyingElement,
921
- )
972
+ if (this != null ) {
973
+ // check that the Store is actually a [FeatureSettings.Store]
974
+ if (this .directSuperTypeReferences()
975
+ .none { it.asClassReferenceOrNull()?.fqName == FeatureSettings .Store ::class .fqName }
976
+ ) {
977
+ throw AnvilCompilationException (
978
+ " ${vmClass.fqName} [settingsStore] must extend [FeatureSettings.Store]" ,
979
+ element = vmClass.clazz.identifyingElement,
980
+ )
981
+ }
982
+
983
+ requireFeatureAndStoreCrossReference(vmClass, this )
922
984
}
923
985
}
924
986
with (annotation.exceptionsStoreOrNull()) {
925
987
exceptionStore = this != null
926
- if (this != null && this .directSuperTypeReferences()
927
- .none { it.asClassReferenceOrNull()?.fqName == FeatureExceptions .Store ::class .fqName }
928
- ) {
929
- throw AnvilCompilationException (
930
- " ${vmClass.fqName} [exceptionsStore] must extend [FeatureExceptions.Store]" ,
931
- element = vmClass.clazz.identifyingElement,
932
- )
988
+ if (this != null ) {
989
+ if (this .directSuperTypeReferences()
990
+ .none { it.asClassReferenceOrNull()?.fqName == FeatureExceptions .Store ::class .fqName }
991
+ ) {
992
+ throw AnvilCompilationException (
993
+ " ${vmClass.fqName} [exceptionsStore] must extend [FeatureExceptions.Store]" ,
994
+ element = vmClass.clazz.identifyingElement,
995
+ )
996
+ }
997
+ requireFeatureAndStoreCrossReference(vmClass, this )
933
998
}
934
999
}
935
1000
with (annotation.toggleStoreOrNull()) {
936
1001
toggleStore = this != null
937
- if (this != null && this .directSuperTypeReferences().none { it.asClassReferenceOrNull()?.fqName == Toggle .Store ::class .fqName }) {
938
- throw AnvilCompilationException (
939
- " ${vmClass.fqName} [toggleStore] must extend [Toggle.Store]" ,
940
- element = vmClass.clazz.identifyingElement,
941
- )
1002
+ if (this != null ) {
1003
+ if (this .directSuperTypeReferences().none { it.asClassReferenceOrNull()?.fqName == Toggle .Store ::class .fqName }) {
1004
+ throw AnvilCompilationException (
1005
+ " ${vmClass.fqName} [toggleStore] must extend [Toggle.Store]" ,
1006
+ element = vmClass.clazz.identifyingElement,
1007
+ )
1008
+ }
1009
+ requireFeatureAndStoreCrossReference(vmClass, this )
942
1010
}
943
1011
}
944
1012
@@ -993,6 +1061,10 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
993
1061
)
994
1062
}
995
1063
1064
+ private fun AnnotationReference.remoteFeatureStoreValueOrNull (): ClassReference ? {
1065
+ return argumentAt(" value" , 0 )?.value()
1066
+ }
1067
+
996
1068
private fun AnnotationReference.featureNameOrNull (): String? {
997
1069
return argumentAt(" featureName" , 2 )?.value()
998
1070
}
0 commit comments