author | darcy |
Thu, 31 Mar 2016 14:56:33 -0700 | |
changeset 36777 | 28d33fb9097f |
parent 25874 | 83c19f00452c |
permissions | -rw-r--r-- |
10 | 1 |
/* |
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
2 |
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. |
10 | 3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
|
5 |
* modification, are permitted provided that the following conditions |
|
6 |
* are met: |
|
7 |
* |
|
8 |
* - Redistributions of source code must retain the above copyright |
|
9 |
* notice, this list of conditions and the following disclaimer. |
|
10 |
* |
|
11 |
* - Redistributions in binary form must reproduce the above copyright |
|
12 |
* notice, this list of conditions and the following disclaimer in the |
|
13 |
* documentation and/or other materials provided with the distribution. |
|
14 |
* |
|
5520 | 15 |
* - Neither the name of Oracle nor the names of its |
10 | 16 |
* contributors may be used to endorse or promote products derived |
17 |
* from this software without specific prior written permission. |
|
18 |
* |
|
19 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
|
20 |
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
21 |
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
22 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
23 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
24 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
25 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
26 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
27 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
28 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
29 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
30 |
*/ |
|
31 |
||
32 |
import java.util.Set; |
|
33 |
import java.util.EnumSet; |
|
34 |
||
35 |
import javax.annotation.processing.*; |
|
36 |
import javax.lang.model.SourceVersion; |
|
37 |
import javax.lang.model.element.*; |
|
38 |
import javax.lang.model.type.*; |
|
39 |
import javax.lang.model.util.*; |
|
40 |
import static javax.lang.model.SourceVersion.*; |
|
41 |
import static javax.lang.model.element.Modifier.*; |
|
42 |
import static javax.lang.model.element.ElementKind.*; |
|
43 |
import static javax.lang.model.type.TypeKind.*; |
|
44 |
import static javax.lang.model.util.ElementFilter.*; |
|
45 |
import static javax.tools.Diagnostic.Kind.*; |
|
46 |
||
47 |
/** |
|
48 |
* A sample processor to check naming conventions are being followed. |
|
49 |
* |
|
50 |
* <h3>How to run this processor from the command line</h3> |
|
51 |
* <ol> |
|
52 |
* <li> Compile this file; for example<br> |
|
53 |
* {@code javac -d procdir CheckNamesProcessor.java} |
|
54 |
* <li> Use {@code javac} to run the annotation processor on itself:<br> |
|
55 |
* {@code javac -processorpath procdir -processor CheckNamesProcessor -proc:only CheckNamesProcessor.java} |
|
56 |
* </ol> |
|
57 |
* |
|
58 |
* <h3>Another way to run this processor from the command line</h3> |
|
59 |
* <ol> |
|
60 |
* <li> Compile the processor as before |
|
61 |
* |
|
62 |
* <li> Create a UTF-8 encoded text file named {@code |
|
63 |
* javax.annotation.processing.Processor} in the {@code |
|
64 |
* META-INF/services} directory. The contents of the file are a list |
|
65 |
* of the binary names of the concrete processor classes, one per |
|
66 |
* line. This provider-configuration file is used by {@linkplain |
|
67 |
* java.util.ServiceLoader service-loader} style lookup. |
|
68 |
* |
|
69 |
* <li> Create a {@code jar} file with the processor classes and |
|
70 |
* {@code META-INF} information. |
|
71 |
* |
|
72 |
* <li> Such a {@code jar} file can now be used with the <i>discovery |
|
73 |
* process</i> without explicitly naming the processor to run:<br> |
|
74 |
* {@code javac -processorpath procdir -proc:only CheckNamesProcessor.java} |
|
75 |
* |
|
76 |
* </ol> |
|
77 |
* |
|
78 |
* <h3>Possible Enhancements</h3> |
|
79 |
* <ul> |
|
80 |
* |
|
81 |
* <li> Support an annotation processor option to control checking |
|
82 |
* exported API elements ({@code public} and {@code protected} ones) |
|
83 |
* or all elements |
|
84 |
* |
|
85 |
* <li> Print out warnings that are more informative |
|
86 |
* |
|
87 |
* <li> Return a true/false status if any warnings were printed or |
|
88 |
* compute and return name warning count |
|
89 |
* |
|
90 |
* <li> Implement checks of package names |
|
91 |
* |
|
92 |
* <li> Use the Tree API, com.sun.source, to examine names within method bodies |
|
93 |
* |
|
94 |
* <li> Define an annotation type whose presence can indicate a |
|
95 |
* different naming convention is being followed |
|
96 |
* |
|
97 |
* <li> Implement customized checks on elements in chosen packages |
|
98 |
* |
|
99 |
* </ul> |
|
100 |
* |
|
101 |
* @author Joseph D. Darcy |
|
102 |
*/ |
|
103 |
@SupportedAnnotationTypes("*") // Process (check) everything |
|
104 |
public class CheckNamesProcessor extends AbstractProcessor { |
|
105 |
private NameChecker nameChecker; |
|
106 |
||
107 |
/** |
|
108 |
* Check that the names of the root elements (and their enclosed |
|
109 |
* elements) follow the appropriate naming conventions. This |
|
110 |
* processor examines all files regardless of whether or not |
|
111 |
* annotations are present; no new source or class files are |
|
112 |
* generated. |
|
113 |
* |
|
114 |
* <p>Processors that actually process specific annotations should |
|
115 |
* <em>not</em> report supporting {@code *}; this could cause |
|
116 |
* performance degradations and other undesirable outcomes. |
|
117 |
*/ |
|
118 |
@Override |
|
119 |
public boolean process(Set<? extends TypeElement> annotations, |
|
120 |
RoundEnvironment roundEnv) { |
|
121 |
if (!roundEnv.processingOver()) { |
|
122 |
for (Element element : roundEnv.getRootElements() ) |
|
123 |
nameChecker.checkNames(element); |
|
124 |
} |
|
125 |
return false; // Allow other processors to examine files too. |
|
126 |
} |
|
127 |
||
128 |
@Override |
|
129 |
public void init(ProcessingEnvironment processingEnv) { |
|
130 |
super.init(processingEnv); |
|
131 |
nameChecker = new NameChecker(processingEnv); |
|
132 |
} |
|
133 |
||
134 |
@Override |
|
135 |
public SourceVersion getSupportedSourceVersion() { |
|
136 |
/* |
|
137 |
* Return latest source version instead of a fixed version |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
138 |
* like RELEASE_9. To return a fixed version, this class could |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
139 |
* be annotated with a SupportedSourceVersion annotation. |
10 | 140 |
* |
141 |
* Warnings will be issued if any unknown language constructs |
|
142 |
* are encountered. |
|
143 |
*/ |
|
144 |
return SourceVersion.latest(); |
|
145 |
} |
|
146 |
||
147 |
/** |
|
148 |
* Provide checks that an element and its enclosed elements follow |
|
149 |
* the usual naming conventions. |
|
150 |
* |
|
9303
eae35c201e19
7032975: API files in javax.annotation.processing need to be updated for references to JLS
jjh
parents:
7681
diff
changeset
|
151 |
* <p> Conventions from section 6.8 of |
eae35c201e19
7032975: API files in javax.annotation.processing need to be updated for references to JLS
jjh
parents:
7681
diff
changeset
|
152 |
* <cite>The Java™ Language Specification</cite> |
10 | 153 |
* |
154 |
* <ul> |
|
155 |
* <li> Classes and interfaces: camel case, first letter is uppercase |
|
156 |
* <li> Methods: camel case, first letter is lowercase |
|
157 |
* <li> Type variables: one uppercase letter |
|
158 |
* <li> Fields |
|
159 |
* <ul> |
|
160 |
* <li> non-final: camel case, initial lowercase |
|
161 |
* <li> constant: uppercase separated by underscores |
|
162 |
* </ul> |
|
9303
eae35c201e19
7032975: API files in javax.annotation.processing need to be updated for references to JLS
jjh
parents:
7681
diff
changeset
|
163 |
* <li> Packages: checks left as exercise for the reader, see section 7.7 of |
eae35c201e19
7032975: API files in javax.annotation.processing need to be updated for references to JLS
jjh
parents:
7681
diff
changeset
|
164 |
* <cite>The Java™ Language Specification</cite>. |
10 | 165 |
* </ul> |
166 |
*/ |
|
167 |
private static class NameChecker { |
|
168 |
private final Messager messager; |
|
169 |
private final Types typeUtils; |
|
170 |
||
171 |
NameCheckScanner nameCheckScanner = new NameCheckScanner(); |
|
172 |
||
173 |
NameChecker(ProcessingEnvironment processsingEnv) { |
|
174 |
this.messager = processsingEnv.getMessager(); |
|
175 |
this.typeUtils = processsingEnv.getTypeUtils(); |
|
176 |
} |
|
177 |
||
178 |
/** |
|
179 |
* If the name of the argument or its enclosed elements |
|
180 |
* violates the naming conventions, report a warning. |
|
181 |
*/ |
|
182 |
public void checkNames(Element element) { |
|
183 |
// Implement name checks with a visitor, but expose that |
|
184 |
// functionality through this method instead. |
|
185 |
nameCheckScanner.scan(element); |
|
186 |
} |
|
187 |
||
188 |
/** |
|
189 |
* Visitor to implement name checks. |
|
190 |
*/ |
|
25690
b1dac768ab79
8050430: Provided new utility visitors supporting SourceVersion.RELEASE_9
darcy
parents:
10192
diff
changeset
|
191 |
private class NameCheckScanner extends ElementScanner9<Void, Void> { |
10 | 192 |
// The visitor could be enhanced to return true/false if |
193 |
// there were warnings reported or a count of the number |
|
194 |
// of warnings. This could be facilitated by using |
|
195 |
// Boolean or Integer instead of Void for the actual type |
|
196 |
// arguments. In more detail, one way to tally the number |
|
197 |
// of warnings would be for each method to return the sum |
|
198 |
// of the warnings it and the methods it called issued, a |
|
199 |
// bottom-up computation. In that case, the first type |
|
200 |
// argument would be Integer and the second type argument |
|
201 |
// would still be Void. Alternatively, the current count |
|
202 |
// could be passed along in Integer parameter p and each |
|
203 |
// method could return the Integer sum of p and the |
|
204 |
// warnings the method issued. Some computations are more |
|
205 |
// naturally expressed in one form instead of the other. |
|
206 |
// If greater control is needed over traversal order, a |
|
207 |
// SimpleElementVisitor can be extended instead of an |
|
208 |
// ElementScanner. |
|
209 |
||
210 |
/** |
|
211 |
* Check the name of a type and its enclosed elements and |
|
212 |
* type parameters. |
|
213 |
*/ |
|
214 |
@Override |
|
215 |
public Void visitType(TypeElement e, Void p) { |
|
216 |
scan(e.getTypeParameters(), p); // Check the names of any type parameters |
|
217 |
checkCamelCase(e, true); // Check the name of the class or interface |
|
218 |
super.visitType(e, p); // Check the names of any enclosed elements |
|
219 |
return null; |
|
220 |
} |
|
221 |
||
222 |
/** |
|
223 |
* Check the name of an executable (method, constructor, |
|
224 |
* etc.) and its type parameters. |
|
225 |
*/ |
|
226 |
@Override |
|
227 |
public Void visitExecutable(ExecutableElement e, Void p) { |
|
228 |
scan(e.getTypeParameters(), p); // Check the names of any type parameters |
|
229 |
||
230 |
// Check the name of the executable |
|
231 |
if (e.getKind() == METHOD) { |
|
232 |
// Make sure that a method does not have the same |
|
233 |
// name as its class or interface. |
|
234 |
Name name = e.getSimpleName(); |
|
235 |
if (name.contentEquals(e.getEnclosingElement().getSimpleName())) |
|
236 |
messager.printMessage(WARNING, |
|
237 |
"A method should not have the same name as its enclosing type, ``" + |
|
238 |
name + "''." , e); |
|
239 |
checkCamelCase(e, false); |
|
240 |
} |
|
241 |
// else constructors and initializers don't have user-defined names |
|
242 |
||
243 |
// At this point, could use the Tree API, |
|
244 |
// com.sun.source, to examine the names of entities |
|
245 |
// inside a method. |
|
246 |
super.visitExecutable(e, p); |
|
247 |
return null; |
|
248 |
} |
|
249 |
||
250 |
/** |
|
251 |
* Check the name of a field, parameter, etc. |
|
252 |
*/ |
|
253 |
@Override |
|
254 |
public Void visitVariable(VariableElement e, Void p) { |
|
255 |
if (!checkForSerial(e)) { // serialVersionUID checks |
|
256 |
// Is the variable a constant? |
|
257 |
if (e.getKind() == ENUM_CONSTANT || |
|
258 |
e.getConstantValue() != null || |
|
259 |
heuristicallyConstant(e) ) |
|
260 |
checkAllCaps(e); // includes enum constants |
|
261 |
else |
|
262 |
checkCamelCase(e, false); |
|
263 |
} |
|
264 |
// A call to super can be elided with the current language definition. |
|
265 |
// super.visitVariable(e, p); |
|
266 |
return null; |
|
267 |
} |
|
268 |
||
269 |
/** |
|
270 |
* Check the name of a type parameter. |
|
271 |
*/ |
|
272 |
@Override |
|
273 |
public Void visitTypeParameter(TypeParameterElement e, Void p) { |
|
274 |
checkAllCaps(e); |
|
275 |
// A call to super can be elided with the current language definition. |
|
276 |
// super.visitTypeParameter(e, p); |
|
277 |
return null; |
|
278 |
} |
|
279 |
||
280 |
/** |
|
281 |
* Check the name of a package. |
|
282 |
*/ |
|
283 |
@Override |
|
284 |
public Void visitPackage(PackageElement e, Void p) { |
|
285 |
/* |
|
286 |
* Implementing the checks of package names is left |
|
9303
eae35c201e19
7032975: API files in javax.annotation.processing need to be updated for references to JLS
jjh
parents:
7681
diff
changeset
|
287 |
* as an exercise for the reader, see JLS section |
10 | 288 |
* 7.7 for conventions. |
289 |
*/ |
|
290 |
||
291 |
// Whether or not this method should call |
|
292 |
// super.visitPackage, to visit the packages enclosed |
|
293 |
// elements, is a design decision based on what a |
|
294 |
// PackageElemement is used to mean in this context. |
|
295 |
// A PackageElement can represent a whole package, so |
|
296 |
// it can provide a concise way to indicate many |
|
297 |
// user-defined types should be visited. However, a |
|
298 |
// PackageElement can also represent a |
|
299 |
// package-info.java file, as would be in the case if |
|
300 |
// the PackageElement came from |
|
301 |
// RoundEnvironment.getRootElements. In that case, |
|
302 |
// the package-info file and other files in that |
|
303 |
// package could be passed in. Therefore, without |
|
304 |
// further checks, types in a package could be visited |
|
305 |
// more than once if a package's elements were visited |
|
306 |
// too. |
|
307 |
return null; |
|
308 |
} |
|
309 |
||
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
310 |
/** |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
311 |
* Check the name of a module. |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
312 |
*/ |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
313 |
@Override |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
314 |
public Void visitModule(ModuleElement e, Void p) { |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
315 |
/* |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
316 |
* Implementing the checks of package names is left as |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
317 |
* an exercise for the reader. |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
318 |
*/ |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
319 |
|
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
320 |
// Similar to the options of how visiting a package |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
321 |
// could be handled, whether or not this method should |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
322 |
// call super and scan, etc. is a design choice on |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
323 |
// whether it is desired for a ModuleElement to |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
324 |
// represent a module-info file or for the |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
325 |
// ModuleElement to represent the entire contents of a |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
326 |
// module, including its packages. |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
327 |
return null; |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
328 |
} |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
329 |
|
10 | 330 |
@Override |
331 |
public Void visitUnknown(Element e, Void p) { |
|
332 |
// This method will be called if a kind of element |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
333 |
// added after JDK 9 is visited. Since as of this |
10 | 334 |
// writing the conventions for such constructs aren't |
335 |
// known, issue a warning. |
|
336 |
messager.printMessage(WARNING, |
|
337 |
"Unknown kind of element, " + e.getKind() + |
|
338 |
", no name checking performed.", e); |
|
339 |
return null; |
|
340 |
} |
|
341 |
||
342 |
// All the name checking methods assume the examined names |
|
343 |
// are syntactically well-formed identifiers. |
|
344 |
||
345 |
/** |
|
346 |
* Return {@code true} if this variable is a field named |
|
347 |
* "serialVersionUID"; false otherwise. A true |
|
348 |
* serialVersionUID of a class has type {@code long} and |
|
349 |
* is static and final. |
|
350 |
* |
|
351 |
* <p>To check that a Serializable class defines a proper |
|
352 |
* serialVersionUID, run javac with -Xlint:serial. |
|
353 |
* |
|
354 |
* @return true if this variable is a serialVersionUID field and false otherwise |
|
355 |
*/ |
|
356 |
private boolean checkForSerial(VariableElement e) { |
|
357 |
// If a field is named "serialVersionUID" ... |
|
358 |
if (e.getKind() == FIELD && |
|
359 |
e.getSimpleName().contentEquals("serialVersionUID")) { |
|
360 |
// ... issue a warning if it does not act as a serialVersionUID |
|
361 |
if (!(e.getModifiers().containsAll(EnumSet.of(STATIC, FINAL)) && |
|
362 |
typeUtils.isSameType(e.asType(), typeUtils.getPrimitiveType(LONG)) && |
|
363 |
e.getEnclosingElement().getKind() == CLASS )) // could check that class implements Serializable |
|
364 |
messager.printMessage(WARNING, |
|
365 |
"Field named ``serialVersionUID'' is not acting as such.", e); |
|
366 |
return true; |
|
367 |
} |
|
368 |
return false; |
|
369 |
} |
|
370 |
||
371 |
/** |
|
372 |
* Using heuristics, return {@code true} is the variable |
|
373 |
* should follow the naming conventions for constants and |
|
374 |
* {@code false} otherwise. For example, the public |
|
375 |
* static final fields ZERO, ONE, and TEN in |
|
376 |
* java.math.BigDecimal are logically constants (and named |
|
377 |
* as constants) even though BigDecimal values are not |
|
378 |
* regarded as constants by the language specification. |
|
379 |
* However, some final fields may not act as constants |
|
380 |
* since the field may be a reference to a mutable object. |
|
381 |
* |
|
382 |
* <p> These heuristics could be tweaked to provide better |
|
383 |
* fidelity. |
|
384 |
* |
|
385 |
* @return true if the current heuristics regard the |
|
386 |
* variable as a constant and false otherwise. |
|
387 |
*/ |
|
388 |
private boolean heuristicallyConstant(VariableElement e) { |
|
389 |
// Fields declared in interfaces are logically |
|
390 |
// constants, JLSv3 section 9.3. |
|
391 |
if (e.getEnclosingElement().getKind() == INTERFACE) |
|
392 |
return true; |
|
393 |
else if (e.getKind() == FIELD && |
|
394 |
e.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL))) |
|
395 |
return true; |
|
396 |
else { |
|
397 |
// A parameter declared final should not be named like |
|
398 |
// a constant, neither should exception parameters. |
|
399 |
return false; |
|
400 |
} |
|
401 |
} |
|
402 |
||
403 |
/** |
|
404 |
* Print a warning if an element's simple name is not in |
|
405 |
* camel case. If there are two adjacent uppercase |
|
406 |
* characters, the name is considered to violate the |
|
407 |
* camel case naming convention. |
|
408 |
* |
|
409 |
* @param e the element whose name will be checked |
|
410 |
* @param initialCaps whether or not the first character should be uppercase |
|
411 |
*/ |
|
412 |
private void checkCamelCase(Element e, boolean initialCaps) { |
|
413 |
String name = e.getSimpleName().toString(); |
|
414 |
boolean previousUpper = false; |
|
415 |
boolean conventional = true; |
|
416 |
int firstCodePoint = name.codePointAt(0); |
|
417 |
||
418 |
if (Character.isUpperCase(firstCodePoint)) { |
|
419 |
previousUpper = true; |
|
420 |
if (!initialCaps) { |
|
421 |
messager.printMessage(WARNING, |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
422 |
"Name ``" + name + "'' should start in lowercase.", e); |
10 | 423 |
return; |
424 |
} |
|
425 |
} else if (Character.isLowerCase(firstCodePoint)) { |
|
426 |
if (initialCaps) { |
|
427 |
messager.printMessage(WARNING, |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
428 |
"Name ``" + name + "'' should start in uppercase.", e); |
10 | 429 |
return; |
430 |
} |
|
431 |
} else // underscore, etc. |
|
432 |
conventional = false; |
|
433 |
||
434 |
if (conventional) { |
|
435 |
int cp = firstCodePoint; |
|
436 |
for (int i = Character.charCount(cp); |
|
437 |
i < name.length(); |
|
438 |
i += Character.charCount(cp)) { |
|
439 |
cp = name.codePointAt(i); |
|
440 |
if (Character.isUpperCase(cp)){ |
|
441 |
if (previousUpper) { |
|
442 |
conventional = false; |
|
443 |
break; |
|
444 |
} |
|
445 |
previousUpper = true; |
|
446 |
} else |
|
447 |
previousUpper = false; |
|
448 |
} |
|
449 |
} |
|
450 |
||
451 |
if (!conventional) |
|
452 |
messager.printMessage(WARNING, |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
453 |
"Name ``" + name + "'', should be in camel case.", e); |
10 | 454 |
} |
455 |
||
456 |
/** |
|
457 |
* Print a warning if the element's name is not a sequence |
|
458 |
* of uppercase letters separated by underscores ("_"). |
|
459 |
* |
|
460 |
* @param e the element whose name will be checked |
|
461 |
*/ |
|
462 |
private void checkAllCaps(Element e) { |
|
463 |
String name = e.getSimpleName().toString(); |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
464 |
/* |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
465 |
* Traditionally type variables are recommended to |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
466 |
* have one-character names. As an exercise for the |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
467 |
* reader, a more nuanced policy can be implemented. |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
468 |
*/ |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
469 |
if (e.getKind() == TYPE_PARAMETER) { |
10 | 470 |
if (name.codePointCount(0, name.length()) > 1 || |
471 |
// Assume names are non-empty |
|
472 |
!Character.isUpperCase(name.codePointAt(0))) |
|
473 |
messager.printMessage(WARNING, |
|
474 |
"A type variable's name,``" + name + |
|
475 |
"'', should be a single uppercace character.", |
|
476 |
e); |
|
477 |
} else { |
|
478 |
boolean conventional = true; |
|
479 |
int firstCodePoint = name.codePointAt(0); |
|
480 |
||
481 |
// Starting with an underscore is not conventional |
|
482 |
if (!Character.isUpperCase(firstCodePoint)) |
|
483 |
conventional = false; |
|
484 |
else { |
|
485 |
// Was the previous character an underscore? |
|
486 |
boolean previousUnderscore = false; |
|
487 |
int cp = firstCodePoint; |
|
488 |
for (int i = Character.charCount(cp); |
|
489 |
i < name.length(); |
|
490 |
i += Character.charCount(cp)) { |
|
491 |
cp = name.codePointAt(i); |
|
492 |
if (cp == (int) '_') { |
|
493 |
if (previousUnderscore) { |
|
494 |
conventional = false; |
|
495 |
break; |
|
496 |
} |
|
497 |
previousUnderscore = true; |
|
498 |
} else { |
|
499 |
previousUnderscore = false; |
|
500 |
if (!Character.isUpperCase(cp) && !Character.isDigit(cp) ) { |
|
501 |
conventional = false; |
|
502 |
break; |
|
503 |
} |
|
504 |
} |
|
505 |
} |
|
506 |
} |
|
507 |
||
508 |
if (!conventional) |
|
509 |
messager.printMessage(WARNING, |
|
510 |
"A constant's name, ``" + name + "'', should be ALL_CAPS.", |
|
511 |
e); |
|
512 |
} |
|
513 |
} |
|
514 |
||
515 |
} |
|
516 |
} |
|
517 |
} |
|
518 |
||
519 |
/** |
|
520 |
* Lots of bad names. Don't write code like this! |
|
36777
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
521 |
* |
28d33fb9097f
6818181: Update naming convention annotation processing samples for modules
darcy
parents:
25874
diff
changeset
|
522 |
* The unmodified name checks will print 11 warnings for this class. |
10 | 523 |
*/ |
524 |
class BADLY_NAMED_CODE { |
|
525 |
enum colors { |
|
526 |
red, |
|
527 |
blue, |
|
528 |
green; |
|
529 |
} |
|
530 |
||
531 |
// Don't start the name of a constant with an underscore |
|
532 |
static final int _FORTY_TWO = 42; |
|
533 |
||
534 |
// Non-constants shouldn't use ALL_CAPS |
|
535 |
public static int NOT_A_CONSTANT = _FORTY_TWO; |
|
536 |
||
537 |
// *Not* a serialVersionUID |
|
538 |
private static final int serialVersionUID = _FORTY_TWO; |
|
539 |
||
540 |
// Not a constructor |
|
541 |
protected void BADLY_NAMED_CODE() { |
|
542 |
return; |
|
543 |
} |
|
544 |
||
545 |
public void NOTcamelCASEmethodNAME() { |
|
546 |
return; |
|
547 |
} |
|
548 |
} |