• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.common.collect.Iterables.getOnlyElement;
20 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
22 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
23 import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
24 import static java.util.stream.Collectors.joining;
25 
26 import androidx.room.compiler.processing.XExecutableElement;
27 import androidx.room.compiler.processing.XMethodElement;
28 import com.google.common.collect.ImmutableMap;
29 import com.google.common.collect.ImmutableSet;
30 import com.squareup.javapoet.ClassName;
31 import dagger.internal.codegen.base.ClearableCache;
32 import java.util.HashMap;
33 import java.util.Map;
34 import javax.inject.Inject;
35 import javax.inject.Singleton;
36 
37 /** Validates any binding method. */
38 @Singleton
39 public final class AnyBindingMethodValidator implements ClearableCache {
40   private final ImmutableMap<ClassName, BindingMethodValidator> validators;
41   private final Map<XMethodElement, ValidationReport> reports = new HashMap<>();
42 
43   @Inject
AnyBindingMethodValidator(ImmutableMap<ClassName, BindingMethodValidator> validators)44   AnyBindingMethodValidator(ImmutableMap<ClassName, BindingMethodValidator> validators) {
45     this.validators = validators;
46   }
47 
48   @Override
clearCache()49   public void clearCache() {
50     reports.clear();
51   }
52 
53   /** Returns the binding method annotations considered by this validator. */
methodAnnotations()54   public ImmutableSet<ClassName> methodAnnotations() {
55     return validators.keySet();
56   }
57 
58   /**
59    * Returns {@code true} if {@code method} is annotated with at least one of {@link
60    * #methodAnnotations()}.
61    */
isBindingMethod(XExecutableElement method)62   public boolean isBindingMethod(XExecutableElement method) {
63     return hasAnyAnnotation(method, methodAnnotations());
64   }
65 
66   /**
67    * Returns a validation report for a method.
68    *
69    * <ul>
70    *   <li>Reports an error if {@code method} is annotated with more than one {@linkplain
71    *       #methodAnnotations() binding method annotation}.
72    *   <li>Validates {@code method} with the {@link BindingMethodValidator} for the single
73    *       {@linkplain #methodAnnotations() binding method annotation}.
74    * </ul>
75    *
76    * @throws IllegalArgumentException if {@code method} is not annotated by any {@linkplain
77    *     #methodAnnotations() binding method annotation}
78    */
validate(XMethodElement method)79   public ValidationReport validate(XMethodElement method) {
80     return reentrantComputeIfAbsent(reports, method, this::validateUncached);
81   }
82 
83   /**
84    * Returns {@code true} if {@code method} was already {@linkplain #validate(XMethodElement)
85    * validated}.
86    */
wasAlreadyValidated(XMethodElement method)87   public boolean wasAlreadyValidated(XMethodElement method) {
88     return reports.containsKey(method);
89   }
90 
validateUncached(XMethodElement method)91   private ValidationReport validateUncached(XMethodElement method) {
92     ValidationReport.Builder report = ValidationReport.about(method);
93     ImmutableSet<ClassName> bindingMethodAnnotations =
94         methodAnnotations().stream().filter(method::hasAnnotation).collect(toImmutableSet());
95     switch (bindingMethodAnnotations.size()) {
96       case 0:
97         throw new IllegalArgumentException(
98             String.format("%s has no binding method annotation", method));
99 
100       case 1:
101         report.addSubreport(
102             validators.get(getOnlyElement(bindingMethodAnnotations)).validate(method));
103         break;
104 
105       default:
106         report.addError(
107             String.format(
108                 "%s is annotated with more than one of (%s)",
109                 getSimpleName(method),
110                 methodAnnotations().stream().map(ClassName::canonicalName).collect(joining(", "))),
111             method);
112         break;
113     }
114     return report.build();
115   }
116 }
117