Coverage Report - com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTagInfo
 
Classes in this File Line Coverage Branch Coverage Complexity
JavadocTagInfo
100%
51/51
100%
8/8
0
JavadocTagInfo$1
100%
3/3
100%
10/10
0
JavadocTagInfo$10
100%
3/3
100%
8/8
0
JavadocTagInfo$11
100%
5/5
100%
4/4
0
JavadocTagInfo$12
100%
4/4
100%
4/4
0
JavadocTagInfo$13
100%
4/4
100%
4/4
0
JavadocTagInfo$14
100%
11/11
100%
14/14
0
JavadocTagInfo$15
100%
6/6
100%
6/6
0
JavadocTagInfo$16
100%
4/4
100%
4/4
0
JavadocTagInfo$17
100%
3/3
100%
4/4
0
JavadocTagInfo$18
100%
4/4
100%
4/4
0
JavadocTagInfo$19
100%
3/3
100%
10/10
0
JavadocTagInfo$2
100%
4/4
100%
4/4
0
JavadocTagInfo$3
100%
4/4
100%
4/4
0
JavadocTagInfo$4
100%
4/4
100%
4/4
0
JavadocTagInfo$5
100%
3/3
100%
4/4
0
JavadocTagInfo$6
100%
7/7
100%
6/6
0
JavadocTagInfo$7
100%
4/4
100%
4/4
0
JavadocTagInfo$8
100%
4/4
100%
4/4
0
JavadocTagInfo$9
100%
4/4
100%
4/4
0
JavadocTagInfo$Type
100%
3/3
N/A
0
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2018 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.checks.javadoc;
 21  
 
 22  
 import java.util.Arrays;
 23  
 import java.util.Collections;
 24  
 import java.util.Map;
 25  
 import java.util.stream.Collectors;
 26  
 
 27  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 28  
 import com.puppycrawl.tools.checkstyle.api.Scope;
 29  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 30  
 import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
 31  
 
 32  
 /**
 33  
  * This enum defines the various Javadoc tags and there properties.
 34  
  *
 35  
  * <p>
 36  
  * This class was modeled after documentation located at
 37  
  * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html">
 38  
  * javadoc</a>
 39  
  *
 40  
  * and
 41  
  *
 42  
  * <a href="http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html">
 43  
  * how to write</a>.
 44  
  * </p>
 45  
  *
 46  
  * <p>
 47  
  * Some of this documentation was a little incomplete (ex: valid placement of
 48  
  * code, value, and literal tags).
 49  
  * </p>
 50  
  *
 51  
  * <p>
 52  
  * Whenever an inconsistency was found the author's judgment was used.
 53  
  * </p>
 54  
  *
 55  
  * <p>
 56  
  * For now, the number of required/optional tag arguments are not included
 57  
  * because some Javadoc tags have very complex rules for determining this
 58  
  * (ex: {@code {@value}} tag).
 59  
  * </p>
 60  
  *
 61  
  * <p>
 62  
  * Also, the {@link #isValidOn(DetailAST) isValidOn} method does not consider
 63  
  * classes defined in a local code block (method, init block, etc.).
 64  
  * </p>
 65  
  *
 66  
  * @author Travis Schneeberger
 67  
  */
 68  115
 public enum JavadocTagInfo {
 69  
 
 70  
     /**
 71  
      * {@code @author}.
 72  
      */
 73  1
     AUTHOR("@author", "author", Type.BLOCK) {
 74  
 
 75  
         @Override
 76  
         public boolean isValidOn(final DetailAST ast) {
 77  6
             final int astType = ast.getType();
 78  6
             return astType == TokenTypes.PACKAGE_DEF
 79  
                 || astType == TokenTypes.CLASS_DEF
 80  
                 || astType == TokenTypes.INTERFACE_DEF
 81  
                 || astType == TokenTypes.ENUM_DEF
 82  
                 || astType == TokenTypes.ANNOTATION_DEF;
 83  
         }
 84  
 
 85  
     },
 86  
 
 87  
     /**
 88  
      * {@code {@code}}.
 89  
      */
 90  1
     CODE("{@code}", "code", Type.INLINE) {
 91  
 
 92  
         @Override
 93  
         public boolean isValidOn(final DetailAST ast) {
 94  10
             final int astType = ast.getType();
 95  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 96  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 97  
         }
 98  
 
 99  
     },
 100  
 
 101  
     /**
 102  
      * {@code {@docRoot}}.
 103  
      */
 104  1
     DOC_ROOT("{@docRoot}", "docRoot", Type.INLINE) {
 105  
 
 106  
         @Override
 107  
         public boolean isValidOn(final DetailAST ast) {
 108  10
             final int astType = ast.getType();
 109  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 110  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 111  
         }
 112  
 
 113  
     },
 114  
 
 115  
     /**
 116  
      * {@code @deprecated}.
 117  
      */
 118  1
     DEPRECATED("@deprecated", "deprecated", Type.BLOCK) {
 119  
 
 120  
         @Override
 121  
         public boolean isValidOn(final DetailAST ast) {
 122  11
             final int astType = ast.getType();
 123  22
             return Arrays.binarySearch(DEF_TOKEN_TYPES_DEPRECATED, astType) >= 0
 124  10
                 && !ScopeUtils.isLocalVariableDef(ast);
 125  
         }
 126  
 
 127  
     },
 128  
 
 129  
     /**
 130  
      * {@code @exception}.
 131  
      */
 132  1
     EXCEPTION("@exception", "exception", Type.BLOCK) {
 133  
 
 134  
         @Override
 135  
         public boolean isValidOn(final DetailAST ast) {
 136  3
             final int astType = ast.getType();
 137  3
             return astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF;
 138  
         }
 139  
 
 140  
     },
 141  
 
 142  
     /**
 143  
      * {@code {@inheritDoc}}.
 144  
      */
 145  1
     INHERIT_DOC("{@inheritDoc}", "inheritDoc", Type.INLINE) {
 146  
 
 147  
         @Override
 148  
         public boolean isValidOn(final DetailAST ast) {
 149  94
             final int astType = ast.getType();
 150  
 
 151  188
             return astType == TokenTypes.METHOD_DEF
 152  92
                 && ast.findFirstToken(TokenTypes.MODIFIERS)
 153  92
                     .findFirstToken(TokenTypes.LITERAL_STATIC) == null
 154  87
                 && ScopeUtils.getScopeFromMods(ast
 155  87
                     .findFirstToken(TokenTypes.MODIFIERS)) != Scope.PRIVATE;
 156  
         }
 157  
 
 158  
     },
 159  
 
 160  
     /**
 161  
      * {@code {@link}}.
 162  
      */
 163  1
     LINK("{@link}", "link", Type.INLINE) {
 164  
 
 165  
         @Override
 166  
         public boolean isValidOn(final DetailAST ast) {
 167  10
             final int astType = ast.getType();
 168  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 169  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 170  
         }
 171  
 
 172  
     },
 173  
 
 174  
     /**
 175  
      * {@code {@linkplain}}.
 176  
      */
 177  1
     LINKPLAIN("{@linkplain}", "linkplain", Type.INLINE) {
 178  
 
 179  
         @Override
 180  
         public boolean isValidOn(final DetailAST ast) {
 181  10
             final int astType = ast.getType();
 182  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 183  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 184  
         }
 185  
 
 186  
     },
 187  
 
 188  
     /**
 189  
      * {@code {@literal}}.
 190  
      */
 191  1
     LITERAL("{@literal}", "literal", Type.INLINE) {
 192  
 
 193  
         @Override
 194  
         public boolean isValidOn(final DetailAST ast) {
 195  10
             final int astType = ast.getType();
 196  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 197  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 198  
         }
 199  
 
 200  
     },
 201  
 
 202  
     /**
 203  
      * {@code @param}.
 204  
      */
 205  1
     PARAM("@param", "param", Type.BLOCK) {
 206  
 
 207  
         @Override
 208  
         public boolean isValidOn(final DetailAST ast) {
 209  5
             final int astType = ast.getType();
 210  5
             return astType == TokenTypes.CLASS_DEF
 211  
                 || astType == TokenTypes.INTERFACE_DEF
 212  
                 || astType == TokenTypes.METHOD_DEF
 213  
                 || astType == TokenTypes.CTOR_DEF;
 214  
         }
 215  
 
 216  
     },
 217  
 
 218  
     /**
 219  
      * {@code @return}.
 220  
      */
 221  1
     RETURN("@return", "return", Type.BLOCK) {
 222  
 
 223  
         @Override
 224  
         public boolean isValidOn(final DetailAST ast) {
 225  3
             final int astType = ast.getType();
 226  3
             final DetailAST returnType = ast.findFirstToken(TokenTypes.TYPE);
 227  
 
 228  6
             return astType == TokenTypes.METHOD_DEF
 229  2
                 && returnType.getFirstChild().getType() != TokenTypes.LITERAL_VOID;
 230  
         }
 231  
 
 232  
     },
 233  
 
 234  
     /**
 235  
      * {@code @see}.
 236  
      */
 237  1
     SEE("@see", "see", Type.BLOCK) {
 238  
 
 239  
         @Override
 240  
         public boolean isValidOn(final DetailAST ast) {
 241  10
             final int astType = ast.getType();
 242  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 243  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 244  
         }
 245  
 
 246  
     },
 247  
 
 248  
     /**
 249  
      * {@code @serial}.
 250  
      */
 251  1
     SERIAL("@serial", "serial", Type.BLOCK) {
 252  
 
 253  
         @Override
 254  
         public boolean isValidOn(final DetailAST ast) {
 255  3
             final int astType = ast.getType();
 256  
 
 257  6
             return astType == TokenTypes.VARIABLE_DEF
 258  2
                 && !ScopeUtils.isLocalVariableDef(ast);
 259  
         }
 260  
 
 261  
     },
 262  
 
 263  
     /**
 264  
      * {@code @serialData}.
 265  
      */
 266  1
     SERIAL_DATA("@serialData", "serialData", Type.BLOCK) {
 267  
 
 268  
         @Override
 269  
         public boolean isValidOn(final DetailAST ast) {
 270  8
             final int astType = ast.getType();
 271  8
             final DetailAST methodNameAst = ast.findFirstToken(TokenTypes.IDENT);
 272  8
             final String methodName = methodNameAst.getText();
 273  
 
 274  16
             return astType == TokenTypes.METHOD_DEF
 275  7
                 && ("writeObject".equals(methodName)
 276  6
                     || "readObject".equals(methodName)
 277  5
                     || "writeExternal".equals(methodName)
 278  4
                     || "readExternal".equals(methodName)
 279  3
                     || "writeReplace".equals(methodName)
 280  2
                     || "readResolve".equals(methodName));
 281  
         }
 282  
 
 283  
     },
 284  
 
 285  
     /**
 286  
      * {@code @serialField}.
 287  
      */
 288  1
     SERIAL_FIELD("@serialField", "serialField", Type.BLOCK) {
 289  
 
 290  
         @Override
 291  
         public boolean isValidOn(final DetailAST ast) {
 292  4
             final int astType = ast.getType();
 293  4
             final DetailAST varType = ast.findFirstToken(TokenTypes.TYPE);
 294  
 
 295  8
             return astType == TokenTypes.VARIABLE_DEF
 296  3
                 && varType.getFirstChild().getType() == TokenTypes.ARRAY_DECLARATOR
 297  2
                 && "ObjectStreamField".equals(varType.getFirstChild().getText());
 298  
         }
 299  
 
 300  
     },
 301  
 
 302  
     /**
 303  
      * {@code @since}.
 304  
      */
 305  1
     SINCE("@since", "since", Type.BLOCK) {
 306  
 
 307  
         @Override
 308  
         public boolean isValidOn(final DetailAST ast) {
 309  10
             final int astType = ast.getType();
 310  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 311  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 312  
         }
 313  
 
 314  
     },
 315  
 
 316  
     /**
 317  
      * {@code @throws}.
 318  
      */
 319  1
     THROWS("@throws", "throws", Type.BLOCK) {
 320  
 
 321  
         @Override
 322  
         public boolean isValidOn(final DetailAST ast) {
 323  3
             final int astType = ast.getType();
 324  3
             return astType == TokenTypes.METHOD_DEF
 325  
                 || astType == TokenTypes.CTOR_DEF;
 326  
         }
 327  
 
 328  
     },
 329  
 
 330  
     /**
 331  
      * {@code {@value}}.
 332  
      */
 333  1
     VALUE("{@value}", "value", Type.INLINE) {
 334  
 
 335  
         @Override
 336  
         public boolean isValidOn(final DetailAST ast) {
 337  10
             final int astType = ast.getType();
 338  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 339  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 340  
         }
 341  
 
 342  
     },
 343  
 
 344  
     /**
 345  
      * {@code @version}.
 346  
      */
 347  1
     VERSION("@version", "version", Type.BLOCK) {
 348  
 
 349  
         @Override
 350  
         public boolean isValidOn(final DetailAST ast) {
 351  6
             final int astType = ast.getType();
 352  6
             return astType == TokenTypes.PACKAGE_DEF
 353  
                 || astType == TokenTypes.CLASS_DEF
 354  
                 || astType == TokenTypes.INTERFACE_DEF
 355  
                 || astType == TokenTypes.ENUM_DEF
 356  
                 || astType == TokenTypes.ANNOTATION_DEF;
 357  
         }
 358  
 
 359  
     };
 360  
 
 361  
     /** Default token types for DEPRECATED Javadoc tag.*/
 362  1
     private static final int[] DEF_TOKEN_TYPES_DEPRECATED = {
 363  
         TokenTypes.CTOR_DEF,
 364  
         TokenTypes.METHOD_DEF,
 365  
         TokenTypes.VARIABLE_DEF,
 366  
         TokenTypes.CLASS_DEF,
 367  
         TokenTypes.INTERFACE_DEF,
 368  
         TokenTypes.ENUM_DEF,
 369  
         TokenTypes.ENUM_CONSTANT_DEF,
 370  
         TokenTypes.ANNOTATION_DEF,
 371  
         TokenTypes.ANNOTATION_FIELD_DEF,
 372  
     };
 373  
 
 374  
     /** Default token types.*/
 375  1
     private static final int[] DEF_TOKEN_TYPES = {
 376  
         TokenTypes.CTOR_DEF,
 377  
         TokenTypes.METHOD_DEF,
 378  
         TokenTypes.VARIABLE_DEF,
 379  
         TokenTypes.CLASS_DEF,
 380  
         TokenTypes.INTERFACE_DEF,
 381  
         TokenTypes.PACKAGE_DEF,
 382  
         TokenTypes.ENUM_DEF,
 383  
         TokenTypes.ANNOTATION_DEF,
 384  
     };
 385  
 
 386  
     /** Holds tag text to tag enum mappings. **/
 387  
     private static final Map<String, JavadocTagInfo> TEXT_TO_TAG;
 388  
     /** Holds tag name to tag enum mappings. **/
 389  
     private static final Map<String, JavadocTagInfo> NAME_TO_TAG;
 390  
 
 391  
     static {
 392  2
         TEXT_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
 393  20
             .collect(Collectors.toMap(JavadocTagInfo::getText, tagText -> tagText)));
 394  2
         NAME_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
 395  20
             .collect(Collectors.toMap(JavadocTagInfo::getName, tagName -> tagName)));
 396  
 
 397  
         //Arrays sorting for binary search
 398  1
         Arrays.sort(DEF_TOKEN_TYPES);
 399  1
         Arrays.sort(DEF_TOKEN_TYPES_DEPRECATED);
 400  1
     }
 401  
 
 402  
     /** The tag text. **/
 403  
     private final String text;
 404  
     /** The tag name. **/
 405  
     private final String name;
 406  
     /** The tag type. **/
 407  
     private final Type type;
 408  
 
 409  
     /**
 410  
      * Sets the various properties of a Javadoc tag.
 411  
      *
 412  
      * @param text the tag text
 413  
      * @param name the tag name
 414  
      * @param type the type of tag
 415  
      */
 416  
     JavadocTagInfo(final String text, final String name,
 417  19
         final Type type) {
 418  19
         this.text = text;
 419  19
         this.name = name;
 420  19
         this.type = type;
 421  19
     }
 422  
 
 423  
     /**
 424  
      * Checks if a particular Javadoc tag is valid within a Javadoc block of a
 425  
      * given AST.
 426  
      *
 427  
      * <p>
 428  
      * If passing in a DetailAST representing a non-void METHOD_DEF
 429  
      * {@code true } would be returned. If passing in a DetailAST
 430  
      * representing a CLASS_DEF {@code false } would be returned because
 431  
      * CLASS_DEF's cannot return a value.
 432  
      * </p>
 433  
      *
 434  
      * @param ast the AST representing a type that can be Javadoc'd
 435  
      * @return true if tag is valid.
 436  
      */
 437  
     public abstract boolean isValidOn(DetailAST ast);
 438  
 
 439  
     /**
 440  
      * Gets the tag text.
 441  
      * @return the tag text
 442  
      */
 443  
     public String getText() {
 444  112
         return text;
 445  
     }
 446  
 
 447  
     /**
 448  
      * Gets the tag name.
 449  
      * @return the tag name
 450  
      */
 451  
     public String getName() {
 452  240
         return name;
 453  
     }
 454  
 
 455  
     /**
 456  
      * Gets the Tag type defined by {@link Type Type}.
 457  
      * @return the Tag type
 458  
      */
 459  
     public Type getType() {
 460  1
         return type;
 461  
     }
 462  
 
 463  
     /**
 464  
      * Returns a JavadocTag from the tag text.
 465  
      * @param text String representing the tag text
 466  
      * @return Returns a JavadocTag type from a String representing the tag
 467  
      * @throws NullPointerException if the text is null
 468  
      * @throws IllegalArgumentException if the text is not a valid tag
 469  
      */
 470  
     public static JavadocTagInfo fromText(final String text) {
 471  3
         if (text == null) {
 472  1
             throw new IllegalArgumentException("the text is null");
 473  
         }
 474  
 
 475  2
         final JavadocTagInfo tag = TEXT_TO_TAG.get(text);
 476  
 
 477  2
         if (tag == null) {
 478  1
             throw new IllegalArgumentException("the text [" + text
 479  
                 + "] is not a valid Javadoc tag text");
 480  
         }
 481  
 
 482  1
         return tag;
 483  
     }
 484  
 
 485  
     /**
 486  
      * Returns a JavadocTag from the tag name.
 487  
      * @param name String name of the tag
 488  
      * @return Returns a JavadocTag type from a String representing the tag
 489  
      * @throws NullPointerException if the text is null
 490  
      * @throws IllegalArgumentException if the text is not a valid tag. The name
 491  
      *     can be checked using {@link JavadocTagInfo#isValidName(String)}
 492  
      */
 493  
     public static JavadocTagInfo fromName(final String name) {
 494  385
         if (name == null) {
 495  1
             throw new IllegalArgumentException("the name is null");
 496  
         }
 497  
 
 498  384
         final JavadocTagInfo tag = NAME_TO_TAG.get(name);
 499  
 
 500  384
         if (tag == null) {
 501  1
             throw new IllegalArgumentException("the name [" + name
 502  
                 + "] is not a valid Javadoc tag name");
 503  
         }
 504  
 
 505  383
         return tag;
 506  
     }
 507  
 
 508  
     /**
 509  
      * Returns whether the provided name is for a valid tag.
 510  
      * @param name the tag name to check.
 511  
      * @return whether the provided name is for a valid tag.
 512  
      */
 513  
     public static boolean isValidName(final String name) {
 514  146
         return NAME_TO_TAG.containsKey(name);
 515  
     }
 516  
 
 517  
     @Override
 518  
     public String toString() {
 519  1
         return "text [" + text + "] name [" + name
 520  
             + "] type [" + type + "]";
 521  
     }
 522  
 
 523  
     /**
 524  
      * The Javadoc Type.
 525  
      *
 526  
      * <p>For example a {@code @param} tag is a block tag while a
 527  
      * {@code {@link}} tag is a inline tag.
 528  
      *
 529  
      * @author Travis Schneeberger
 530  
      */
 531  6
     public enum Type {
 532  
 
 533  
         /** Block type. **/
 534  1
         BLOCK,
 535  
 
 536  
         /** Inline type. **/
 537  1
         INLINE
 538  
 
 539  
     }
 540  
 
 541  
 }