1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreElements; 19 import com.google.common.base.Predicate; 20 import com.google.common.collect.FluentIterable; 21 import com.google.common.collect.ImmutableSet; 22 import java.util.Set; 23 import javax.inject.Inject; 24 import javax.lang.model.element.AnnotationMirror; 25 import javax.lang.model.element.ExecutableElement; 26 import javax.lang.model.element.Modifier; 27 import javax.lang.model.element.TypeElement; 28 import javax.lang.model.element.VariableElement; 29 import javax.lang.model.util.ElementFilter; 30 31 import static com.google.auto.common.MoreElements.isAnnotationPresent; 32 import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS; 33 import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_INNER_CLASS; 34 import static dagger.internal.codegen.ErrorMessages.INJECT_INTO_PRIVATE_CLASS; 35 import static dagger.internal.codegen.ErrorMessages.INJECT_ON_PRIVATE_CONSTRUCTOR; 36 import static dagger.internal.codegen.ErrorMessages.MULTIPLE_INJECT_CONSTRUCTORS; 37 import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS; 38 import static dagger.internal.codegen.ErrorMessages.MULTIPLE_SCOPES; 39 import static dagger.internal.codegen.ErrorMessages.QUALIFIER_ON_INJECT_CONSTRUCTOR; 40 import static dagger.internal.codegen.InjectionAnnotations.getQualifiers; 41 import static dagger.internal.codegen.InjectionAnnotations.getScopes; 42 import static javax.lang.model.element.Modifier.ABSTRACT; 43 import static javax.lang.model.element.Modifier.PRIVATE; 44 import static javax.lang.model.element.Modifier.STATIC; 45 46 /** 47 * A {@linkplain ValidationReport validator} for {@link Inject} constructors. 48 * 49 * @author Gregory Kick 50 * @since 2.0 51 */ 52 final class InjectConstructorValidator { validate(ExecutableElement constructorElement)53 ValidationReport<TypeElement> validate(ExecutableElement constructorElement) { 54 ValidationReport.Builder<TypeElement> builder = 55 ValidationReport.about(MoreElements.asType(constructorElement.getEnclosingElement())); 56 if (constructorElement.getModifiers().contains(PRIVATE)) { 57 builder.addError(INJECT_ON_PRIVATE_CONSTRUCTOR, constructorElement); 58 } 59 60 for (AnnotationMirror qualifier : getQualifiers(constructorElement)) { 61 builder.addError(QUALIFIER_ON_INJECT_CONSTRUCTOR, constructorElement, qualifier); 62 } 63 64 for (VariableElement parameter : constructorElement.getParameters()) { 65 ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(parameter); 66 if (qualifiers.size() > 1) { 67 for (AnnotationMirror qualifier : qualifiers) { 68 builder.addError(MULTIPLE_QUALIFIERS, constructorElement, qualifier); 69 } 70 } 71 } 72 73 TypeElement enclosingElement = 74 MoreElements.asType(constructorElement.getEnclosingElement()); 75 Set<Modifier> typeModifiers = enclosingElement.getModifiers(); 76 77 if (typeModifiers.contains(PRIVATE)) { 78 builder.addError(INJECT_INTO_PRIVATE_CLASS, constructorElement); 79 } 80 81 if (typeModifiers.contains(ABSTRACT)) { 82 builder.addError(INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS, constructorElement); 83 } 84 85 if (enclosingElement.getNestingKind().isNested() 86 && !typeModifiers.contains(STATIC)) { 87 builder.addError(INJECT_CONSTRUCTOR_ON_INNER_CLASS, constructorElement); 88 } 89 90 // This is computationally expensive, but probably preferable to a giant index 91 FluentIterable<ExecutableElement> injectConstructors = FluentIterable.from( 92 ElementFilter.constructorsIn(enclosingElement.getEnclosedElements())) 93 .filter(new Predicate<ExecutableElement>() { 94 @Override public boolean apply(ExecutableElement input) { 95 return isAnnotationPresent(input, Inject.class); 96 } 97 }); 98 99 if (injectConstructors.size() > 1) { 100 builder.addError(MULTIPLE_INJECT_CONSTRUCTORS, constructorElement); 101 } 102 103 ImmutableSet<? extends AnnotationMirror> scopes = getScopes(enclosingElement); 104 if (scopes.size() > 1) { 105 for (AnnotationMirror scope : scopes) { 106 builder.addError(MULTIPLE_SCOPES, enclosingElement, scope); 107 } 108 } 109 110 return builder.build(); 111 } 112 } 113