• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.processor.internal;
18 
19 import com.google.auto.common.MoreTypes;
20 import com.google.common.base.Preconditions;
21 import com.google.common.collect.ImmutableList;
22 import com.google.errorprone.annotations.FormatMethod;
23 import com.google.errorprone.annotations.FormatString;
24 import java.util.Collection;
25 import java.util.stream.Collectors;
26 import javax.annotation.Nullable;
27 import javax.lang.model.element.Element;
28 import javax.lang.model.element.TypeElement;
29 import javax.lang.model.type.TypeKind;
30 import javax.lang.model.type.TypeMirror;
31 
32 /** Static helper methods for throwing errors during code generation. */
33 public final class ProcessorErrors {
34   /**
35    * Ensures the truth of an expression involving the state of the calling instance, but not
36    * involving any parameters to the calling method.
37    *
38    * @param expression a boolean expression
39    * @param errorMessage the exception message to use if the check fails; will be converted to a
40    *     string using {@link String#valueOf(Object)}
41    * @throws BadInputException if {@code expression} is false
42    */
checkState( boolean expression, @Nullable Object errorMessage)43   public static void checkState(
44       boolean expression,
45       @Nullable Object errorMessage) {
46     if (!expression) {
47       throw new BadInputException(String.valueOf(errorMessage));
48     }
49   }
50 
51   /**
52    * Ensures the truth of an expression involving the state of the calling instance, but not
53    * involving any parameters to the calling method.
54    *
55    * @param expression a boolean expression
56    * @param errorMessageTemplate a template for the exception message should the check fail. The
57    *     message is formed by replacing each {@code %s} placeholder in the template with an
58    *     argument. These are matched by position - the first {@code %s} gets {@code
59    *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
60    *     square braces. Unmatched placeholders will be left as-is.
61    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
62    *     are converted to strings using {@link String#valueOf(Object)}.
63    * @throws BadInputException if {@code expression} is false
64    * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
65    *     {@code errorMessageArgs} is null (don't let this happen)
66    */
67   @FormatMethod
checkState( boolean expression, @Nullable @FormatString String errorMessageTemplate, @Nullable Object... errorMessageArgs)68   public static void checkState(
69       boolean expression,
70       @Nullable @FormatString String errorMessageTemplate,
71       @Nullable Object... errorMessageArgs) {
72     if (!expression) {
73       throw new BadInputException(String.format(errorMessageTemplate, errorMessageArgs));
74     }
75   }
76 
77   /**
78    * Ensures the truth of an expression involving the state of the calling instance, but not
79    * involving any parameters to the calling method.
80    *
81    * @param expression a boolean expression
82    * @param badElement the element that was at fault
83    * @param errorMessage the exception message to use if the check fails; will be converted to a
84    *     string using {@link String#valueOf(Object)}
85    * @throws BadInputException if {@code expression} is false
86    */
checkState( boolean expression, Element badElement, @Nullable Object errorMessage)87   public static void checkState(
88       boolean expression,
89       Element badElement,
90       @Nullable Object errorMessage) {
91     Preconditions.checkNotNull(badElement);
92     if (!expression) {
93       throw new BadInputException(String.valueOf(errorMessage), badElement);
94     }
95   }
96 
97   /**
98    * Ensures the truth of an expression involving the state of the calling instance, but not
99    * involving any parameters to the calling method.
100    *
101    * <p>e.g. checkState(foo.isABar(), "Failed because of %s is not a bar", foo);
102    *
103    * @param expression a boolean expression
104    * @param badElement the element that was at fault
105    * @param errorMessageTemplate a template for the exception message should the check fail. The
106    *     message is formed by replacing each {@code %s} placeholder in the template with an
107    *     argument. These are matched by position - the first {@code %s} gets {@code
108    *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
109    *     square braces. Unmatched placeholders will be left as-is.
110    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
111    *     are converted to strings using {@link String#valueOf(Object)}.
112    * @throws BadInputException if {@code expression} is false
113    * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
114    *     {@code errorMessageArgs} is null (don't let this happen)
115    */
116   @FormatMethod
checkState( boolean expression, Element badElement, @Nullable @FormatString String errorMessageTemplate, @Nullable Object... errorMessageArgs)117   public static void checkState(
118       boolean expression,
119       Element badElement,
120       @Nullable @FormatString String errorMessageTemplate,
121       @Nullable Object... errorMessageArgs) {
122     Preconditions.checkNotNull(badElement);
123     if (!expression) {
124       throw new BadInputException(
125           String.format(errorMessageTemplate, errorMessageArgs), badElement);
126     }
127   }
128 
129   /**
130    * Ensures the truth of an expression involving the state of the calling instance, but not
131    * involving any parameters to the calling method.
132    *
133    * @param expression a boolean expression
134    * @param badElements the element that were at fault
135    * @param errorMessage the exception message to use if the check fails; will be converted to a
136    *     string using {@link String#valueOf(Object)}
137    * @throws BadInputException if {@code expression} is false
138    */
checkState( boolean expression, Collection<? extends Element> badElements, @Nullable Object errorMessage)139   public static void checkState(
140       boolean expression,
141       Collection<? extends Element> badElements,
142       @Nullable Object errorMessage) {
143     Preconditions.checkNotNull(badElements);
144     if (!expression) {
145       Preconditions.checkState(!badElements.isEmpty());
146       throw new BadInputException(String.valueOf(errorMessage), badElements);
147     }
148   }
149 
150   /**
151    * Ensures the truth of an expression involving the state of the calling instance, but not
152    * involving any parameters to the calling method.
153    *
154    * @param expression a boolean expression
155    * @param badElements the elements that were at fault
156    * @param errorMessageTemplate a template for the exception message should the check fail. The
157    *     message is formed by replacing each {@code %s} placeholder in the template with an
158    *     argument. These are matched by position - the first {@code %s} gets {@code
159    *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
160    *     square braces. Unmatched placeholders will be left as-is.
161    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
162    *     are converted to strings using {@link String#valueOf(Object)}.
163    * @throws BadInputException if {@code expression} is false
164    * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
165    *     {@code errorMessageArgs} is null (don't let this happen)
166    */
167   @FormatMethod
checkState( boolean expression, Collection<? extends Element> badElements, @Nullable @FormatString String errorMessageTemplate, @Nullable Object... errorMessageArgs)168   public static void checkState(
169       boolean expression,
170       Collection<? extends Element> badElements,
171       @Nullable @FormatString String errorMessageTemplate,
172       @Nullable Object... errorMessageArgs) {
173     Preconditions.checkNotNull(badElements);
174     if (!expression) {
175       Preconditions.checkState(!badElements.isEmpty());
176       throw new BadInputException(
177           String.format(errorMessageTemplate, errorMessageArgs), badElements);
178     }
179   }
180 
181   /**
182    * Ensures that the given element is not an error kind and does not inherit from an error kind.
183    *
184    * @param element the element to check
185    * @throws ErrorTypeException if {@code element} inherits from an error kind.
186    */
checkNotErrorKind(TypeElement element)187   public static void checkNotErrorKind(TypeElement element) {
188     TypeMirror currType = element.asType();
189     ImmutableList.Builder<String> typeHierarchy = ImmutableList.builder();
190     while (currType.getKind() != TypeKind.NONE) {
191       typeHierarchy.add(currType.toString());
192       if (currType.getKind() == TypeKind.ERROR) {
193         throw new ErrorTypeException(
194             String.format(
195                 "%s, type hierarchy contains error kind, %s."
196                 + "\n\tThe partially resolved hierarchy is:\n\t\t%s",
197                 element,
198                 currType,
199                 typeHierarchy.build().stream().collect(Collectors.joining(" -> "))),
200             element);
201       }
202       currType = MoreTypes.asTypeElement(currType).getSuperclass();
203     }
204   }
205 
ProcessorErrors()206   private ProcessorErrors() {}
207 }
208