< prev index next >

src/sample/share/javac/processing/src/CheckNamesProcessor.java

Print this page


   1 /*
   2  * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
   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  *
  15  *   - Neither the name of Oracle nor the names of its
  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


  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  * For some notes on how to run an annotation processor inside
  79  * NetBeans, see http://wiki.java.net/bin/view/Netbeans/FaqApt.
  80  *
  81  * <h3>Possible Enhancements</h3>
  82  * <ul>
  83  *
  84  * <li> Support an annotation processor option to control checking
  85  * exported API elements ({@code public} and {@code protected} ones)
  86  * or all elements
  87  *
  88  * <li> Print out warnings that are more informative
  89  *
  90  * <li> Return a true/false status if any warnings were printed or
  91  * compute and return name warning count
  92  *
  93  * <li> Implement checks of package names
  94  *
  95  * <li> Use the Tree API, com.sun.source, to examine names within method bodies
  96  *
  97  * <li> Define an annotation type whose presence can indicate a
  98  * different naming convention is being followed
  99  *
 100  * <li> Implement customized checks on elements in chosen packages


 121     @Override
 122     public boolean process(Set<? extends TypeElement> annotations,
 123             RoundEnvironment roundEnv) {
 124         if (!roundEnv.processingOver()) {
 125             for (Element element : roundEnv.getRootElements() )
 126                 nameChecker.checkNames(element);
 127         }
 128         return false; // Allow other processors to examine files too.
 129     }
 130 
 131     @Override
 132     public void init(ProcessingEnvironment processingEnv) {
 133         super.init(processingEnv);
 134         nameChecker = new NameChecker(processingEnv);
 135     }
 136 
 137     @Override
 138     public SourceVersion getSupportedSourceVersion() {
 139         /*
 140          * Return latest source version instead of a fixed version
 141          * like RELEASE_9.  To return a fixed version, this class
 142          * could be annotated with a SupportedSourceVersion
 143          * annotation.
 144          *
 145          * Warnings will be issued if any unknown language constructs
 146          * are encountered.
 147          */
 148         return SourceVersion.latest();
 149     }
 150 
 151     /**
 152      * Provide checks that an element and its enclosed elements follow
 153      * the usual naming conventions.
 154      *
 155      * <p> Conventions from section 6.8 of
 156      *     <cite>The Java&trade; Language Specification</cite>
 157      *
 158      * <ul>
 159      * <li> Classes and interfaces: camel case, first letter is uppercase
 160      * <li> Methods: camel case, first letter is lowercase
 161      * <li> Type variables: one uppercase letter
 162      * <li> Fields
 163      * <ul>


 294 
 295                 // Whether or not this method should call
 296                 // super.visitPackage, to visit the packages enclosed
 297                 // elements, is a design decision based on what a
 298                 // PackageElemement is used to mean in this context.
 299                 // A PackageElement can represent a whole package, so
 300                 // it can provide a concise way to indicate many
 301                 // user-defined types should be visited.  However, a
 302                 // PackageElement can also represent a
 303                 // package-info.java file, as would be in the case if
 304                 // the PackageElement came from
 305                 // RoundEnvironment.getRootElements.  In that case,
 306                 // the package-info file and other files in that
 307                 // package could be passed in.  Therefore, without
 308                 // further checks, types in a package could be visited
 309                 // more than once if a package's elements were visited
 310                 // too.
 311                 return null;
 312             }
 313 




















 314             @Override
 315             public Void visitUnknown(Element e, Void p) {
 316                 // This method will be called if a kind of element
 317                 // added after JDK 7 is visited.  Since as of this
 318                 // writing the conventions for such constructs aren't
 319                 // known, issue a warning.
 320                 messager.printMessage(WARNING,
 321                                       "Unknown kind of element, " + e.getKind() +
 322                                       ", no name checking performed.", e);
 323                 return null;
 324             }
 325 
 326             // All the name checking methods assume the examined names
 327             // are syntactically well-formed identifiers.
 328 
 329             /**
 330              * Return {@code true} if this variable is a field named
 331              * "serialVersionUID"; false otherwise.  A true
 332              * serialVersionUID of a class has type {@code long} and
 333              * is static and final.
 334              *
 335              * <p>To check that a Serializable class defines a proper
 336              * serialVersionUID, run javac with -Xlint:serial.
 337              *


 386 
 387             /**
 388              * Print a warning if an element's simple name is not in
 389              * camel case.  If there are two adjacent uppercase
 390              * characters, the name is considered to violate the
 391              * camel case naming convention.
 392              *
 393              * @param e the element whose name will be checked
 394              * @param initialCaps whether or not the first character should be uppercase
 395              */
 396             private void checkCamelCase(Element e, boolean initialCaps) {
 397                 String name = e.getSimpleName().toString();
 398                 boolean previousUpper = false;
 399                 boolean conventional = true;
 400                 int firstCodePoint = name.codePointAt(0);
 401 
 402                 if (Character.isUpperCase(firstCodePoint)) {
 403                     previousUpper = true;
 404                     if (!initialCaps) {
 405                         messager.printMessage(WARNING,
 406                                               "Name, ``" + name + "'', should start in lowercase.", e);
 407                         return;
 408                     }
 409                 } else if (Character.isLowerCase(firstCodePoint)) {
 410                     if (initialCaps) {
 411                         messager.printMessage(WARNING,
 412                                               "Name, ``" + name + "'', should start in uppercase.", e);
 413                         return;
 414                     }
 415                 } else // underscore, etc.
 416                     conventional = false;
 417 
 418                 if (conventional) {
 419                     int cp = firstCodePoint;
 420                     for (int i = Character.charCount(cp);
 421                          i < name.length();
 422                          i += Character.charCount(cp)) {
 423                         cp = name.codePointAt(i);
 424                         if (Character.isUpperCase(cp)){
 425                             if (previousUpper) {
 426                                 conventional = false;
 427                                 break;
 428                             }
 429                             previousUpper = true;
 430                         } else
 431                             previousUpper = false;
 432                     }
 433                 }
 434 
 435                 if (!conventional)
 436                     messager.printMessage(WARNING,
 437                                           "Name, ``" + name + "'', should be in camel case.", e);
 438             }
 439 
 440             /**
 441              * Print a warning if the element's name is not a sequence
 442              * of uppercase letters separated by underscores ("_").
 443              *
 444              * @param e the element whose name will be checked
 445              */
 446             private void checkAllCaps(Element e) {
 447                 String name = e.getSimpleName().toString();
 448                 if (e.getKind() == TYPE_PARAMETER) { // Should be one character





 449                     if (name.codePointCount(0, name.length()) > 1 ||
 450                         // Assume names are non-empty
 451                         !Character.isUpperCase(name.codePointAt(0)))
 452                         messager.printMessage(WARNING,
 453                                               "A type variable's name,``" + name +
 454                                               "'', should be a single uppercace character.",
 455                                               e);
 456                 } else {
 457                     boolean conventional = true;
 458                     int firstCodePoint = name.codePointAt(0);
 459 
 460                     // Starting with an underscore is not conventional
 461                     if (!Character.isUpperCase(firstCodePoint))
 462                         conventional = false;
 463                     else {
 464                         // Was the previous character an underscore?
 465                         boolean previousUnderscore = false;
 466                         int cp = firstCodePoint;
 467                         for (int i = Character.charCount(cp);
 468                              i < name.length();


 480                                     conventional = false;
 481                                     break;
 482                                 }
 483                             }
 484                         }
 485                     }
 486 
 487                     if (!conventional)
 488                         messager.printMessage(WARNING,
 489                                               "A constant's name, ``" + name + "'', should be ALL_CAPS.",
 490                                               e);
 491                 }
 492             }
 493 
 494         }
 495     }
 496 }
 497 
 498 /**
 499  * Lots of bad names.  Don't write code like this!


 500  */
 501 class BADLY_NAMED_CODE {
 502     enum colors {
 503         red,
 504         blue,
 505         green;
 506     }
 507 
 508     // Don't start the name of a constant with an underscore
 509     static final int _FORTY_TWO = 42;
 510 
 511     // Non-constants shouldn't use ALL_CAPS
 512     public static int NOT_A_CONSTANT = _FORTY_TWO;
 513 
 514     // *Not* a serialVersionUID
 515     private static final int serialVersionUID = _FORTY_TWO;
 516 
 517     // Not a constructor
 518     protected void BADLY_NAMED_CODE() {
 519         return;
   1 /*
   2  * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
   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  *
  15  *   - Neither the name of Oracle nor the names of its
  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


  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


 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
 138          * like RELEASE_9. To return a fixed version, this class could
 139          * be annotated with a SupportedSourceVersion annotation.

 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      *
 151      * <p> Conventions from section 6.8 of
 152      *     <cite>The Java&trade; Language Specification</cite>
 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>


 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 
 310             /**
 311              * Check the name of a module.
 312              */
 313             @Override
 314             public Void visitModule(ModuleElement e, Void p) {
 315                 /*
 316                  * Implementing the checks of package names is left as
 317                  * an exercise for the reader.
 318                  */
 319 
 320                 // Similar to the options of how visiting a package
 321                 // could be handled, whether or not this method should
 322                 // call super and scan, etc. is a design choice on
 323                 // whether it is desired for a ModuleElement to
 324                 // represent a module-info file or for the
 325                 // ModuleElement to represent the entire contents of a
 326                 // module, including its packages.
 327                 return null;
 328             }
 329 
 330             @Override
 331             public Void visitUnknown(Element e, Void p) {
 332                 // This method will be called if a kind of element
 333                 // added after JDK 9 is visited.  Since as of this
 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              *


 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,
 422                                               "Name ``" + name + "'' should start in lowercase.", e);
 423                         return;
 424                     }
 425                 } else if (Character.isLowerCase(firstCodePoint)) {
 426                     if (initialCaps) {
 427                         messager.printMessage(WARNING,
 428                                               "Name ``" + name + "'' should start in uppercase.", e);
 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,
 453                                           "Name ``" + name + "'', should be in camel case.", e);
 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();
 464                 /*
 465                  * Traditionally type variables are recommended to
 466                  * have one-character names. As an exercise for the
 467                  * reader, a more nuanced policy can be implemented.
 468                  */
 469                 if (e.getKind() == TYPE_PARAMETER) {
 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();


 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!
 521  *
 522  * The unmodified name checks will print 11 warnings for this class.
 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;
< prev index next >