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-2017 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  
         @Override
 75  
         public boolean isValidOn(final DetailAST ast) {
 76  6
             final int astType = ast.getType();
 77  6
             return astType == TokenTypes.PACKAGE_DEF
 78  
                 || astType == TokenTypes.CLASS_DEF
 79  
                 || astType == TokenTypes.INTERFACE_DEF
 80  
                 || astType == TokenTypes.ENUM_DEF
 81  
                 || astType == TokenTypes.ANNOTATION_DEF;
 82  
         }
 83  
     },
 84  
 
 85  
     /**
 86  
      * {@code {@code}}.
 87  
      */
 88  1
     CODE("{@code}", "code", Type.INLINE) {
 89  
         @Override
 90  
         public boolean isValidOn(final DetailAST ast) {
 91  10
             final int astType = ast.getType();
 92  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 93  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 94  
         }
 95  
     },
 96  
 
 97  
     /**
 98  
      * {@code {@docRoot}}.
 99  
      */
 100  1
     DOC_ROOT("{@docRoot}", "docRoot", Type.INLINE) {
 101  
         @Override
 102  
         public boolean isValidOn(final DetailAST ast) {
 103  10
             final int astType = ast.getType();
 104  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 105  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 106  
         }
 107  
     },
 108  
 
 109  
     /**
 110  
      * {@code @deprecated}.
 111  
      */
 112  1
     DEPRECATED("@deprecated", "deprecated", Type.BLOCK) {
 113  
         @Override
 114  
         public boolean isValidOn(final DetailAST ast) {
 115  11
             final int astType = ast.getType();
 116  22
             return Arrays.binarySearch(DEF_TOKEN_TYPES_DEPRECATED, astType) >= 0
 117  10
                 && !ScopeUtils.isLocalVariableDef(ast);
 118  
         }
 119  
     },
 120  
 
 121  
     /**
 122  
      * {@code @exception}.
 123  
      */
 124  1
     EXCEPTION("@exception", "exception", Type.BLOCK) {
 125  
         @Override
 126  
         public boolean isValidOn(final DetailAST ast) {
 127  3
             final int astType = ast.getType();
 128  3
             return astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF;
 129  
         }
 130  
     },
 131  
 
 132  
     /**
 133  
      * {@code {@inheritDoc}}.
 134  
      */
 135  1
     INHERIT_DOC("{@inheritDoc}", "inheritDoc", Type.INLINE) {
 136  
         @Override
 137  
         public boolean isValidOn(final DetailAST ast) {
 138  94
             final int astType = ast.getType();
 139  
 
 140  188
             return astType == TokenTypes.METHOD_DEF
 141  92
                 && ast.findFirstToken(TokenTypes.MODIFIERS)
 142  92
                     .findFirstToken(TokenTypes.LITERAL_STATIC) == null
 143  87
                 && ScopeUtils.getScopeFromMods(ast
 144  87
                     .findFirstToken(TokenTypes.MODIFIERS)) != Scope.PRIVATE;
 145  
         }
 146  
     },
 147  
 
 148  
     /**
 149  
      * {@code {@link}}.
 150  
      */
 151  1
     LINK("{@link}", "link", Type.INLINE) {
 152  
         @Override
 153  
         public boolean isValidOn(final DetailAST ast) {
 154  10
             final int astType = ast.getType();
 155  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 156  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 157  
         }
 158  
     },
 159  
 
 160  
     /**
 161  
      * {@code {@linkplain}}.
 162  
      */
 163  1
     LINKPLAIN("{@linkplain}", "linkplain", Type.INLINE) {
 164  
         @Override
 165  
         public boolean isValidOn(final DetailAST ast) {
 166  10
             final int astType = ast.getType();
 167  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 168  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 169  
         }
 170  
     },
 171  
 
 172  
     /**
 173  
      * {@code {@literal}}.
 174  
      */
 175  1
     LITERAL("{@literal}", "literal", Type.INLINE) {
 176  
         @Override
 177  
         public boolean isValidOn(final DetailAST ast) {
 178  10
             final int astType = ast.getType();
 179  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 180  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 181  
         }
 182  
     },
 183  
 
 184  
     /**
 185  
      * {@code @param}.
 186  
      */
 187  1
     PARAM("@param", "param", Type.BLOCK) {
 188  
         @Override
 189  
         public boolean isValidOn(final DetailAST ast) {
 190  5
             final int astType = ast.getType();
 191  5
             return astType == TokenTypes.CLASS_DEF
 192  
                 || astType == TokenTypes.INTERFACE_DEF
 193  
                 || astType == TokenTypes.METHOD_DEF
 194  
                 || astType == TokenTypes.CTOR_DEF;
 195  
         }
 196  
     },
 197  
 
 198  
     /**
 199  
      * {@code @return}.
 200  
      */
 201  1
     RETURN("@return", "return", Type.BLOCK) {
 202  
         @Override
 203  
         public boolean isValidOn(final DetailAST ast) {
 204  3
             final int astType = ast.getType();
 205  3
             final DetailAST returnType = ast.findFirstToken(TokenTypes.TYPE);
 206  
 
 207  6
             return astType == TokenTypes.METHOD_DEF
 208  2
                 && returnType.getFirstChild().getType() != TokenTypes.LITERAL_VOID;
 209  
 
 210  
         }
 211  
     },
 212  
 
 213  
     /**
 214  
      * {@code @see}.
 215  
      */
 216  1
     SEE("@see", "see", Type.BLOCK) {
 217  
         @Override
 218  
         public boolean isValidOn(final DetailAST ast) {
 219  10
             final int astType = ast.getType();
 220  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 221  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 222  
         }
 223  
     },
 224  
 
 225  
     /**
 226  
      * {@code @serial}.
 227  
      */
 228  1
     SERIAL("@serial", "serial", Type.BLOCK) {
 229  
         @Override
 230  
         public boolean isValidOn(final DetailAST ast) {
 231  3
             final int astType = ast.getType();
 232  
 
 233  6
             return astType == TokenTypes.VARIABLE_DEF
 234  2
                 && !ScopeUtils.isLocalVariableDef(ast);
 235  
         }
 236  
     },
 237  
 
 238  
     /**
 239  
      * {@code @serialData}.
 240  
      */
 241  1
     SERIAL_DATA("@serialData", "serialData", Type.BLOCK) {
 242  
         @Override
 243  
         public boolean isValidOn(final DetailAST ast) {
 244  8
             final int astType = ast.getType();
 245  8
             final DetailAST methodNameAst = ast.findFirstToken(TokenTypes.IDENT);
 246  8
             final String methodName = methodNameAst.getText();
 247  
 
 248  16
             return astType == TokenTypes.METHOD_DEF
 249  7
                 && ("writeObject".equals(methodName)
 250  6
                     || "readObject".equals(methodName)
 251  5
                     || "writeExternal".equals(methodName)
 252  4
                     || "readExternal".equals(methodName)
 253  3
                     || "writeReplace".equals(methodName)
 254  2
                     || "readResolve".equals(methodName));
 255  
         }
 256  
     },
 257  
 
 258  
     /**
 259  
      * {@code @serialField}.
 260  
      */
 261  1
     SERIAL_FIELD("@serialField", "serialField", Type.BLOCK) {
 262  
         @Override
 263  
         public boolean isValidOn(final DetailAST ast) {
 264  4
             final int astType = ast.getType();
 265  4
             final DetailAST varType = ast.findFirstToken(TokenTypes.TYPE);
 266  
 
 267  8
             return astType == TokenTypes.VARIABLE_DEF
 268  3
                 && varType.getFirstChild().getType() == TokenTypes.ARRAY_DECLARATOR
 269  2
                 && "ObjectStreamField".equals(varType.getFirstChild().getText());
 270  
         }
 271  
     },
 272  
 
 273  
     /**
 274  
      * {@code @since}.
 275  
      */
 276  1
     SINCE("@since", "since", Type.BLOCK) {
 277  
         @Override
 278  
         public boolean isValidOn(final DetailAST ast) {
 279  10
             final int astType = ast.getType();
 280  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 281  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 282  
         }
 283  
     },
 284  
 
 285  
     /**
 286  
      * {@code @throws}.
 287  
      */
 288  1
     THROWS("@throws", "throws", Type.BLOCK) {
 289  
         @Override
 290  
         public boolean isValidOn(final DetailAST ast) {
 291  3
             final int astType = ast.getType();
 292  3
             return astType == TokenTypes.METHOD_DEF
 293  
                 || astType == TokenTypes.CTOR_DEF;
 294  
         }
 295  
     },
 296  
 
 297  
     /**
 298  
      * {@code {@value}}.
 299  
      */
 300  1
     VALUE("{@value}", "value", Type.INLINE) {
 301  
         @Override
 302  
         public boolean isValidOn(final DetailAST ast) {
 303  10
             final int astType = ast.getType();
 304  20
             return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0
 305  9
                 && !ScopeUtils.isLocalVariableDef(ast);
 306  
         }
 307  
     },
 308  
 
 309  
     /**
 310  
      * {@code @version}.
 311  
      */
 312  1
     VERSION("@version", "version", Type.BLOCK) {
 313  
         @Override
 314  
         public boolean isValidOn(final DetailAST ast) {
 315  6
             final int astType = ast.getType();
 316  6
             return astType == TokenTypes.PACKAGE_DEF
 317  
                 || astType == TokenTypes.CLASS_DEF
 318  
                 || astType == TokenTypes.INTERFACE_DEF
 319  
                 || astType == TokenTypes.ENUM_DEF
 320  
                 || astType == TokenTypes.ANNOTATION_DEF;
 321  
         }
 322  
     };
 323  
 
 324  
     /** Default token types for DEPRECATED Javadoc tag.*/
 325  1
     private static final int[] DEF_TOKEN_TYPES_DEPRECATED = {
 326  
         TokenTypes.CTOR_DEF,
 327  
         TokenTypes.METHOD_DEF,
 328  
         TokenTypes.VARIABLE_DEF,
 329  
         TokenTypes.CLASS_DEF,
 330  
         TokenTypes.INTERFACE_DEF,
 331  
         TokenTypes.ENUM_DEF,
 332  
         TokenTypes.ENUM_CONSTANT_DEF,
 333  
         TokenTypes.ANNOTATION_DEF,
 334  
         TokenTypes.ANNOTATION_FIELD_DEF,
 335  
     };
 336  
 
 337  
     /** Default token types.*/
 338  1
     private static final int[] DEF_TOKEN_TYPES = {
 339  
         TokenTypes.CTOR_DEF,
 340  
         TokenTypes.METHOD_DEF,
 341  
         TokenTypes.VARIABLE_DEF,
 342  
         TokenTypes.CLASS_DEF,
 343  
         TokenTypes.INTERFACE_DEF,
 344  
         TokenTypes.PACKAGE_DEF,
 345  
         TokenTypes.ENUM_DEF,
 346  
         TokenTypes.ANNOTATION_DEF,
 347  
     };
 348  
 
 349  
     /** Holds tag text to tag enum mappings. **/
 350  
     private static final Map<String, JavadocTagInfo> TEXT_TO_TAG;
 351  
     /** Holds tag name to tag enum mappings. **/
 352  
     private static final Map<String, JavadocTagInfo> NAME_TO_TAG;
 353  
 
 354  
     static {
 355  2
         TEXT_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
 356  20
             .collect(Collectors.toMap(JavadocTagInfo::getText, tagText -> tagText)));
 357  2
         NAME_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values())
 358  20
             .collect(Collectors.toMap(JavadocTagInfo::getName, tagName -> tagName)));
 359  
 
 360  
         //Arrays sorting for binary search
 361  1
         Arrays.sort(DEF_TOKEN_TYPES);
 362  1
         Arrays.sort(DEF_TOKEN_TYPES_DEPRECATED);
 363  1
     }
 364  
 
 365  
     /** The tag text. **/
 366  
     private final String text;
 367  
     /** The tag name. **/
 368  
     private final String name;
 369  
     /** The tag type. **/
 370  
     private final Type type;
 371  
 
 372  
     /**
 373  
      * Sets the various properties of a Javadoc tag.
 374  
      *
 375  
      * @param text the tag text
 376  
      * @param name the tag name
 377  
      * @param type the type of tag
 378  
      */
 379  
     JavadocTagInfo(final String text, final String name,
 380  19
         final Type type) {
 381  19
         this.text = text;
 382  19
         this.name = name;
 383  19
         this.type = type;
 384  19
     }
 385  
 
 386  
     /**
 387  
      * Checks if a particular Javadoc tag is valid within a Javadoc block of a
 388  
      * given AST.
 389  
      *
 390  
      * <p>
 391  
      * If passing in a DetailAST representing a non-void METHOD_DEF
 392  
      * {@code true } would be returned. If passing in a DetailAST
 393  
      * representing a CLASS_DEF {@code false } would be returned because
 394  
      * CLASS_DEF's cannot return a value.
 395  
      * </p>
 396  
      *
 397  
      * @param ast the AST representing a type that can be Javadoc'd
 398  
      * @return true if tag is valid.
 399  
      */
 400  
     public abstract boolean isValidOn(DetailAST ast);
 401  
 
 402  
     /**
 403  
      * Gets the tag text.
 404  
      * @return the tag text
 405  
      */
 406  
     public String getText() {
 407  109
         return text;
 408  
     }
 409  
 
 410  
     /**
 411  
      * Gets the tag name.
 412  
      * @return the tag name
 413  
      */
 414  
     public String getName() {
 415  240
         return name;
 416  
     }
 417  
 
 418  
     /**
 419  
      * Gets the Tag type defined by {@link Type Type}.
 420  
      * @return the Tag type
 421  
      */
 422  
     public Type getType() {
 423  1
         return type;
 424  
     }
 425  
 
 426  
     /**
 427  
      * Returns a JavadocTag from the tag text.
 428  
      * @param text String representing the tag text
 429  
      * @return Returns a JavadocTag type from a String representing the tag
 430  
      * @throws NullPointerException if the text is null
 431  
      * @throws IllegalArgumentException if the text is not a valid tag
 432  
      */
 433  
     public static JavadocTagInfo fromText(final String text) {
 434  3
         if (text == null) {
 435  1
             throw new IllegalArgumentException("the text is null");
 436  
         }
 437  
 
 438  2
         final JavadocTagInfo tag = TEXT_TO_TAG.get(text);
 439  
 
 440  2
         if (tag == null) {
 441  1
             throw new IllegalArgumentException("the text [" + text
 442  
                 + "] is not a valid Javadoc tag text");
 443  
         }
 444  
 
 445  1
         return tag;
 446  
     }
 447  
 
 448  
     /**
 449  
      * Returns a JavadocTag from the tag name.
 450  
      * @param name String name of the tag
 451  
      * @return Returns a JavadocTag type from a String representing the tag
 452  
      * @throws NullPointerException if the text is null
 453  
      * @throws IllegalArgumentException if the text is not a valid tag. The name
 454  
      *     can be checked using {@link JavadocTagInfo#isValidName(String)}
 455  
      */
 456  
     public static JavadocTagInfo fromName(final String name) {
 457  385
         if (name == null) {
 458  1
             throw new IllegalArgumentException("the name is null");
 459  
         }
 460  
 
 461  384
         final JavadocTagInfo tag = NAME_TO_TAG.get(name);
 462  
 
 463  384
         if (tag == null) {
 464  1
             throw new IllegalArgumentException("the name [" + name
 465  
                 + "] is not a valid Javadoc tag name");
 466  
         }
 467  
 
 468  383
         return tag;
 469  
     }
 470  
 
 471  
     /**
 472  
      * Returns whether the provided name is for a valid tag.
 473  
      * @param name the tag name to check.
 474  
      * @return whether the provided name is for a valid tag.
 475  
      */
 476  
     public static boolean isValidName(final String name) {
 477  146
         return NAME_TO_TAG.containsKey(name);
 478  
     }
 479  
 
 480  
     @Override
 481  
     public String toString() {
 482  1
         return "text [" + text + "] name [" + name
 483  
             + "] type [" + type + "]";
 484  
     }
 485  
 
 486  
     /**
 487  
      * The Javadoc Type.
 488  
      *
 489  
      * <p>For example a {@code @param} tag is a block tag while a
 490  
      * {@code {@link}} tag is a inline tag.
 491  
      *
 492  
      * @author Travis Schneeberger
 493  
      */
 494  6
     public enum Type {
 495  
         /** Block type. **/
 496  1
         BLOCK,
 497  
 
 498  
         /** Inline type. **/
 499  1
         INLINE
 500  
     }
 501  
 }