1 /* 2 * Copyright (C) 2016 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.internal.codegen.validation; 18 19 import static dagger.internal.codegen.base.FrameworkTypes.isFrameworkType; 20 import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS; 21 import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING; 22 import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT; 23 import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS; 24 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; 25 import static dagger.internal.codegen.xprocessing.XTypes.isWildcard; 26 27 import androidx.room.compiler.processing.XMethodElement; 28 import androidx.room.compiler.processing.XProcessingEnv; 29 import com.google.common.collect.ImmutableSet; 30 import dagger.internal.codegen.base.MapType; 31 import dagger.internal.codegen.base.SetType; 32 import dagger.internal.codegen.binding.InjectionAnnotations; 33 import dagger.internal.codegen.javapoet.TypeNames; 34 import javax.inject.Inject; 35 36 /** A validator for {@link dagger.multibindings.Multibinds} methods. */ 37 class MultibindsMethodValidator extends BindingMethodValidator { 38 39 /** Creates a validator for {@link dagger.multibindings.Multibinds @Multibinds} methods. */ 40 @Inject MultibindsMethodValidator( XProcessingEnv processingEnv, DependencyRequestValidator dependencyRequestValidator, InjectionAnnotations injectionAnnotations)41 MultibindsMethodValidator( 42 XProcessingEnv processingEnv, 43 DependencyRequestValidator dependencyRequestValidator, 44 InjectionAnnotations injectionAnnotations) { 45 super( 46 TypeNames.MULTIBINDS, 47 ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE), 48 MUST_BE_ABSTRACT, 49 NO_EXCEPTIONS, 50 NO_MULTIBINDINGS, 51 NO_SCOPING, 52 processingEnv, 53 dependencyRequestValidator, 54 injectionAnnotations); 55 } 56 57 @Override elementValidator(XMethodElement method)58 protected ElementValidator elementValidator(XMethodElement method) { 59 return new Validator(method); 60 } 61 62 private class Validator extends MethodValidator { 63 private final XMethodElement method; 64 Validator(XMethodElement method)65 Validator(XMethodElement method) { 66 super(method); 67 this.method = method; 68 } 69 70 @Override checkParameters()71 protected void checkParameters() { 72 if (!method.getParameters().isEmpty()) { 73 report.addError(bindingMethods("cannot have parameters")); 74 } 75 } 76 77 /** Adds an error unless the method returns a {@code Map<K, V>} or {@code Set<T>}. */ 78 @Override checkType()79 protected void checkType() { 80 if (MapType.isMap(method.getReturnType())) { 81 checkMapType(MapType.from(method.getReturnType())); 82 } else if (SetType.isSet(method.getReturnType())) { 83 checkSetType(SetType.from(method.getReturnType())); 84 } else { 85 report.addError(bindingMethods("return type must be either a Set or Map type.")); 86 } 87 } 88 checkMapType(MapType mapType)89 private void checkMapType(MapType mapType) { 90 if (mapType.isRawType()) { 91 report.addError(bindingMethods("return type cannot be a raw Map type")); 92 } else if (isWildcard(mapType.keyType())) { 93 report.addError( 94 bindingMethods("return type cannot use a wildcard as the Map key type.")); 95 } else if (isWildcard(mapType.valueType())) { 96 report.addError( 97 bindingMethods("return type cannot use a wildcard as the Map value type.")); 98 } else if (isFrameworkType(mapType.valueType())) { 99 String frameworkTypeName = getSimpleName(mapType.valueType().getTypeElement()); 100 report.addError( 101 bindingMethods( 102 "return type cannot use '%s' in the Map value type.", frameworkTypeName)); 103 } 104 } 105 checkSetType(SetType setType)106 private void checkSetType(SetType setType) { 107 if (setType.isRawType()) { 108 report.addError(bindingMethods("return type cannot be a raw Set type")); 109 } else if (isWildcard(setType.elementType())) { 110 report.addError(bindingMethods("return type cannot use a wildcard as the Set value type.")); 111 } else if (isFrameworkType(setType.elementType())) { 112 String frameworkTypeName = getSimpleName(setType.elementType().getTypeElement()); 113 report.addError( 114 bindingMethods( 115 "return type cannot use '%s' in the Set value type.", frameworkTypeName)); 116 } 117 } 118 } 119 } 120