1 36 37 import java.util.Set ; 38 import java.util.EnumSet ; 39 40 import javax.annotation.processing.*; 41 import javax.lang.model.SourceVersion; 42 import javax.lang.model.element.*; 43 import javax.lang.model.type.*; 44 import javax.lang.model.util.*; 45 import static javax.lang.model.SourceVersion.*; 46 import static javax.lang.model.element.Modifier.*; 47 import static javax.lang.model.element.ElementKind.*; 48 import static javax.lang.model.type.TypeKind.*; 49 import static javax.lang.model.util.ElementFilter.*; 50 import static javax.tools.Diagnostic.Kind.*; 51 52 111 @SupportedAnnotationTypes("*") public class CheckNamesProcessor extends AbstractProcessor { 113 private NameChecker nameChecker; 114 115 126 @Override  127 public boolean process(Set <? extends TypeElement> annotations, 128 RoundEnvironment roundEnv) { 129 if (!roundEnv.processingOver()) { 130 for (Element element : roundEnv.getRootElements() ) 131 nameChecker.checkNames(element); 132 } 133 return false; } 135 136 @Override  137 public void init(ProcessingEnvironment processingEnv) { 138 super.init(processingEnv); 139 nameChecker = new NameChecker(processingEnv); 140 } 141 142 @Override  143 public SourceVersion getSupportedSourceVersion() { 144 153 return SourceVersion.latest(); 154 } 155 156 174 private static class NameChecker { 175 private final Messager messager; 176 private final Types typeUtils; 177 178 NameCheckScanner nameCheckScanner = new NameCheckScanner(); 179 180 NameChecker(ProcessingEnvironment processsingEnv) { 181 this.messager = processsingEnv.getMessager(); 182 this.typeUtils = processsingEnv.getTypeUtils(); 183 } 184 185 189 public void checkNames(Element element) { 190 nameCheckScanner.scan(element); 193 } 194 195 198 private class NameCheckScanner extends ElementScanner6<Void , Void > { 199 217 221 @Override  222 public Void visitType(TypeElement e, Void p) { 223 scan(e.getTypeParameters(), p); checkCamelCase(e, true); super.visitType(e, p); return null; 227 } 228 229 233 @Override  234 public Void visitExecutable(ExecutableElement e, Void p) { 235 scan(e.getTypeParameters(), p); 237 if (e.getKind() == METHOD) { 239 Name name = e.getSimpleName(); 242 if (name.contentEquals(e.getEnclosingElement().getSimpleName())) 243 messager.printMessage(WARNING, 244 "A method should not have the same name as its enclosing type, ``" + 245 name + "''." , e); 246 checkCamelCase(e, false); 247 } 248 250 super.visitExecutable(e, p); 254 return null; 255 } 256 257 260 @Override  261 public Void visitVariable(VariableElement e, Void p) { 262 if (!checkForSerial(e)) { if (e.getKind() == ENUM_CONSTANT || 265 e.getConstantValue() != null || 266 heuristicallyConstant(e) ) 267 checkAllCaps(e); else 269 checkCamelCase(e, false); 270 } 271 return null; 274 } 275 276 279 @Override  280 public Void visitTypeParameter(TypeParameterElement e, Void p) { 281 checkAllCaps(e); 282 return null; 285 } 286 287 290 @Override  291 public Void visitPackage(PackageElement e, Void p) { 292 297 298 return null; 315 } 316 317 @Override  318 public Void visitUnknown(Element e, Void p) { 319 messager.printMessage(WARNING, 324 "Unknown kind of element, " + e.getKind() + 325 ", no name checking performed.", e); 326 return null; 327 } 328 329 332 343 private boolean checkForSerial(VariableElement e) { 344 if (e.getKind() == FIELD && 346 e.getSimpleName().contentEquals("serialVersionUID")) { 347 if (!(e.getModifiers().containsAll(EnumSet.of(STATIC, FINAL)) && 349 typeUtils.isSameType(e.asType(), typeUtils.getPrimitiveType(LONG)) && 350 e.getEnclosingElement().getKind() == CLASS )) messager.printMessage(WARNING, 352 "Field named ``serialVersionUID'' is not acting as such.", e); 353 return true; 354 } 355 return false; 356 } 357 358 375 private boolean heuristicallyConstant(VariableElement e) { 376 if (e.getEnclosingElement().getKind() == INTERFACE) 379 return true; 380 else if (e.getKind() == FIELD && 381 e.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL))) 382 return true; 383 else { 384 return false; 387 } 388 } 389 390 399 private void checkCamelCase(Element e, boolean initialCaps) { 400 String name = e.getSimpleName().toString(); 401 boolean previousUpper = false; 402 boolean conventional = true; 403 int firstCodePoint = name.codePointAt(0); 404 405 if (Character.isUpperCase(firstCodePoint)) { 406 previousUpper = true; 407 if (!initialCaps) { 408 messager.printMessage(WARNING, 409 "Name, ``" + name + "'', should start in lowercase.", e); 410 return; 411 } 412 } else if (Character.isLowerCase(firstCodePoint)) { 413 if (initialCaps) { 414 messager.printMessage(WARNING, 415 "Name, ``" + name + "'', should start in uppercase.", e); 416 return; 417 } 418 } else conventional = false; 420 421 if (conventional) { 422 int cp = firstCodePoint; 423 for (int i = Character.charCount(cp); 424 i < name.length(); 425 i += Character.charCount(cp)) { 426 cp = name.codePointAt(i); 427 if (Character.isUpperCase(cp)){ 428 if (previousUpper) { 429 conventional = false; 430 break; 431 } 432 previousUpper = true; 433 } else 434 previousUpper = false; 435 } 436 } 437 438 if (!conventional) 439 messager.printMessage(WARNING, 440 "Name, ``" + name + "'', should be in camel case.", e); 441 } 442 443 449 private void checkAllCaps(Element e) { 450 String name = e.getSimpleName().toString(); 451 if (e.getKind() == TYPE_PARAMETER) { if (name.codePointCount(0, name.length()) > 1 || 453 !Character.isUpperCase(name.codePointAt(0))) 455 messager.printMessage(WARNING, 456 "A type variable's name,``" + name + 457 "'', should be a single uppercace character.", 458 e); 459 } else { 460 boolean conventional = true; 461 int firstCodePoint = name.codePointAt(0); 462 463 if (!Character.isUpperCase(firstCodePoint)) 465 conventional = false; 466 else { 467 boolean previousUnderscore = false; 469 int cp = firstCodePoint; 470 for (int i = Character.charCount(cp); 471 i < name.length(); 472 i += Character.charCount(cp)) { 473 cp = name.codePointAt(i); 474 if (cp == (int) '_') { 475 if (previousUnderscore) { 476 conventional = false; 477 break; 478 } 479 previousUnderscore = true; 480 } else { 481 previousUnderscore = false; 482 if (!Character.isUpperCase(cp) && !Character.isDigit(cp) ) { 483 conventional = false; 484 break; 485 } 486 } 487 } 488 } 489 490 if (!conventional) 491 messager.printMessage(WARNING, 492 "A constant's name, ``" + name + "'', should be ALL_CAPS.", 493 e); 494 } 495 } 496 497 } 498 } 499 } 500 501 504 class BADLY_NAMED_CODE { 505 enum colors { 506 red, 507 blue, 508 green; 509 } 510 511 static final int _FORTY_TWO = 42; 513 514 public static int NOT_A_CONSTANT = _FORTY_TWO; 516 517 private static final int serialVersionUID = _FORTY_TWO; 519 520 protected void BADLY_NAMED_CODE() { 522 return; 523 } 524 525 public void NOTcamelCASEmethodNAME() { 526 return; 527 } 528 } 529 | Popular Tags |