1 /* <lambda>null2 * Copyright (C) 2020 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.hilt.android.processor.internal.viewmodel 18 19 import com.google.auto.common.MoreElements 20 import com.squareup.javapoet.ClassName 21 import dagger.hilt.android.processor.internal.AndroidClassNames 22 import dagger.hilt.processor.internal.ClassNames 23 import dagger.hilt.processor.internal.ProcessorErrors 24 import dagger.hilt.processor.internal.Processors 25 import javax.annotation.processing.ProcessingEnvironment 26 import javax.lang.model.element.Modifier 27 import javax.lang.model.element.NestingKind 28 import javax.lang.model.element.TypeElement 29 import javax.lang.model.util.ElementFilter 30 31 /** 32 * Data class that represents a Hilt injected ViewModel 33 */ 34 internal class ViewModelMetadata private constructor( 35 val typeElement: TypeElement 36 ) { 37 val className = ClassName.get(typeElement) 38 39 val modulesClassName = ClassName.get( 40 MoreElements.getPackage(typeElement).qualifiedName.toString(), 41 "${className.simpleNames().joinToString("_")}_HiltModules" 42 ) 43 44 companion object { 45 internal fun create( 46 processingEnv: ProcessingEnvironment, 47 typeElement: TypeElement, 48 ): ViewModelMetadata? { 49 val types = processingEnv.typeUtils 50 val elements = processingEnv.elementUtils 51 52 ProcessorErrors.checkState( 53 types.isSubtype( 54 typeElement.asType(), 55 elements.getTypeElement(AndroidClassNames.VIEW_MODEL.toString()).asType() 56 ), 57 typeElement, 58 "@HiltViewModel is only supported on types that subclass %s.", 59 AndroidClassNames.VIEW_MODEL 60 ) 61 62 ElementFilter.constructorsIn(typeElement.enclosedElements).filter { constructor -> 63 ProcessorErrors.checkState( 64 !Processors.hasAnnotation(constructor, ClassNames.ASSISTED_INJECT), 65 constructor, 66 "ViewModel constructor should be annotated with @Inject instead of @AssistedInject." 67 ) 68 Processors.hasAnnotation(constructor, ClassNames.INJECT) 69 }.let { injectConstructors -> 70 ProcessorErrors.checkState( 71 injectConstructors.size == 1, 72 typeElement, 73 "@HiltViewModel annotated class should contain exactly one @Inject " + 74 "annotated constructor." 75 ) 76 77 injectConstructors.forEach { constructor -> 78 ProcessorErrors.checkState( 79 !constructor.modifiers.contains(Modifier.PRIVATE), 80 constructor, 81 "@Inject annotated constructors must not be private." 82 ) 83 } 84 } 85 86 ProcessorErrors.checkState( 87 typeElement.nestingKind != NestingKind.MEMBER || 88 typeElement.modifiers.contains(Modifier.STATIC), 89 typeElement, 90 "@HiltViewModel may only be used on inner classes if they are static." 91 ) 92 93 Processors.getScopeAnnotations(typeElement).let { scopeAnnotations -> 94 ProcessorErrors.checkState( 95 scopeAnnotations.isEmpty(), 96 typeElement, 97 "@HiltViewModel classes should not be scoped. Found: %s", 98 scopeAnnotations.joinToString() 99 ) 100 } 101 102 return ViewModelMetadata( 103 typeElement 104 ) 105 } 106 } 107 } 108