ProvidesMethodValidator.java revision 5d3207ac2713386ed61c6ca8f0356e8f093a62e1
15d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin/* 25d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Copyright (C) 2014 Google, Inc. 35d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 45d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 55d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * you may not use this file except in compliance with the License. 65d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * You may obtain a copy of the License at 75d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 85d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 95d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Unless required by applicable law or agreed to in writing, software 115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * See the License for the specific language governing permissions and 145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * limitations under the License. 155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */ 165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinpackage dagger.internal.codegen; 175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.ImmutableSet; 195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.Iterables; 205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport dagger.Module; 215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport dagger.Provides; 225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.util.Set; 235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.AnnotationMirror; 245d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.Element; 255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.ExecutableElement; 265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.Modifier; 275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.TypeElement; 285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.type.DeclaredType; 295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.type.TypeKind; 305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.type.TypeMirror; 315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.util.Elements; 325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.auto.common.MoreElements.isAnnotationPresent; 345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.common.base.Preconditions.checkArgument; 355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull; 365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT; 375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE; 385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE; 395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_MAP_HAS_MAP_KEY; 405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE; 415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET; 425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER; 435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_MULTIPLE_MAP_KEY; 445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_NO_MAP_KEY; 455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_RETURN_TYPE; 465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_SET_VALUES_RETURN_SET; 475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS; 485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.InjectionAnnotations.getQualifiers; 495d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static dagger.internal.codegen.MapKeys.getMapKeys; 505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.ABSTRACT; 515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.PRIVATE; 525d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.type.TypeKind.ARRAY; 535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.type.TypeKind.DECLARED; 545d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.type.TypeKind.VOID; 555d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 565d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin/** 575d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * A {@linkplain ValidationReport validator} for {@link Provides} methods. 585d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 595d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * @author Gregory Kick 605d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * @since 2.0 615d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */ 625d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinfinal class ProvidesMethodValidator { 635d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private final Elements elements; 645d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 655d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ProvidesMethodValidator(Elements elements) { 665d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin this.elements = checkNotNull(elements); 675d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 685d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 695d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private TypeElement getSetElement() { 705d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return elements.getTypeElement(Set.class.getCanonicalName()); 715d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 725d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 735d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ValidationReport<ExecutableElement> validate(ExecutableElement providesMethodElement) { 745d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ValidationReport.Builder<ExecutableElement> builder = 755d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ValidationReport.about(providesMethodElement); 765d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 775d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Provides providesAnnotation = providesMethodElement.getAnnotation(Provides.class); 785d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin checkArgument(providesAnnotation != null); 795d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 805d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Element enclosingElement = providesMethodElement.getEnclosingElement(); 815d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!isAnnotationPresent(enclosingElement, Module.class)) { 825d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 835d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE), providesMethodElement); 845d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 855d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 865d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!providesMethodElement.getTypeParameters().isEmpty()) { 875d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER), providesMethodElement); 885d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 895d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 905d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Set<Modifier> modifiers = providesMethodElement.getModifiers(); 915d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (modifiers.contains(PRIVATE)) { 925d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(formatErrorMessage(BINDING_METHOD_PRIVATE), providesMethodElement); 935d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 945d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (modifiers.contains(ABSTRACT)) { 955d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(formatErrorMessage(BINDING_METHOD_ABSTRACT), providesMethodElement); 965d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 975d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 985d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin TypeMirror returnType = providesMethodElement.getReturnType(); 995d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin TypeKind returnTypeKind = returnType.getKind(); 1005d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (returnTypeKind.equals(VOID)) { 1015d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 1025d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE), providesMethodElement); 1035d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1045d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1055d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin // check mapkey is right 1065d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!providesAnnotation.type().equals(Provides.Type.MAP) 1075d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin && !getMapKeys(providesMethodElement).isEmpty()) { 1085d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 1095d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatErrorMessage(BINDING_METHOD_NOT_MAP_HAS_MAP_KEY), providesMethodElement); 1105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin validateMethodQualifiers(builder, providesMethodElement); 1135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin switch (providesAnnotation.type()) { 1155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case UNIQUE: // fall through 1165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case SET: 1175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin validateKeyType(builder, returnType); 1185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case MAP: 1205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin validateKeyType(builder, returnType); 1215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(providesMethodElement); 1225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin switch (mapKeys.size()) { 1235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case 0: 1245d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 1255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatErrorMessage(BINDING_METHOD_WITH_NO_MAP_KEY), providesMethodElement); 1265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case 1: 1285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin default: 1305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 1315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatErrorMessage(BINDING_METHOD_WITH_MULTIPLE_MAP_KEY), providesMethodElement); 1325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case SET_VALUES: 1365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!returnTypeKind.equals(DECLARED)) { 1375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement); 1385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } else { 1395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin DeclaredType declaredReturnType = (DeclaredType) returnType; 1405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin // TODO(gak): should we allow "covariant return" for set values? 1415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!declaredReturnType.asElement().equals(getSetElement())) { 1425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement); 1435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } else if (declaredReturnType.getTypeArguments().isEmpty()) { 1445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError( 1455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET), providesMethodElement); 1465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } else { 1475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin validateKeyType(builder, 1485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Iterables.getOnlyElement(declaredReturnType.getTypeArguments())); 1495d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 1525d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin default: 1535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin throw new AssertionError(); 1545d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1555d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1565d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return builder.build(); 1575d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1585d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1595d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin /** Validates that a Provides or Produces method doesn't have multiple qualifiers. */ 1605d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin static void validateMethodQualifiers(ValidationReport.Builder<ExecutableElement> builder, 1615d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ExecutableElement methodElement) { 1625d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(methodElement); 1635d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (qualifiers.size() > 1) { 1645d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin for (AnnotationMirror qualifier : qualifiers) { 1655d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin builder.addError(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS, methodElement, qualifier); 1665d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1675d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1685d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1695d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1705d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private String formatErrorMessage(String msg) { 1715d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return String.format(msg, Provides.class.getSimpleName()); 1725d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1735d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1745d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private String formatModuleErrorMessage(String msg) { 1755d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return String.format(msg, Provides.class.getSimpleName(), Module.class.getSimpleName()); 1765d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1775d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1785d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private void validateKeyType(ValidationReport.Builder<? extends Element> reportBuilder, 1795d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin TypeMirror type) { 1805d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin TypeKind kind = type.getKind(); 1815d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!(kind.isPrimitive() || kind.equals(DECLARED) || kind.equals(ARRAY))) { 1825d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin reportBuilder.addError(PROVIDES_METHOD_RETURN_TYPE, reportBuilder.getSubject()); 1835d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1845d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1855d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin} 186