Coverage Report - com.puppycrawl.tools.checkstyle.checks.javadoc.WriteTagCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
WriteTagCheck
100%
40/40
100%
14/14
1.778
 
 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.regex.Matcher;
 23  
 import java.util.regex.Pattern;
 24  
 
 25  
 import com.puppycrawl.tools.checkstyle.StatelessCheck;
 26  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 27  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 28  
 import com.puppycrawl.tools.checkstyle.api.FileContents;
 29  
 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
 30  
 import com.puppycrawl.tools.checkstyle.api.TextBlock;
 31  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 32  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 33  
 
 34  
 /**
 35  
  * <p>
 36  
  * Outputs a JavaDoc tag as information. Can be used e.g. with the stylesheets
 37  
  * that sort the report by author name.
 38  
  * To define the format for a tag, set property tagFormat to a
 39  
  * regular expression.
 40  
  * This check uses two different severity levels. The normal one is used for
 41  
  * reporting when the tag is missing. The additional one (tagSeverity) is used
 42  
  * for the level of reporting when the tag exists. The default value for
 43  
  * tagSeverity is info.
 44  
  * </p>
 45  
  * <p> An example of how to configure the check for printing author name is:
 46  
  *</p>
 47  
  * <pre>
 48  
  * &lt;module name="WriteTag"&gt;
 49  
  *    &lt;property name="tag" value="@author"/&gt;
 50  
  *    &lt;property name="tagFormat" value="\S"/&gt;
 51  
  * &lt;/module&gt;
 52  
  * </pre>
 53  
  * <p> An example of how to configure the check to print warnings if an
 54  
  * "@incomplete" tag is found, and not print anything if it is not found:
 55  
  *</p>
 56  
  * <pre>
 57  
  * &lt;module name="WriteTag"&gt;
 58  
  *    &lt;property name="tag" value="@incomplete"/&gt;
 59  
  *    &lt;property name="tagFormat" value="\S"/&gt;
 60  
  *    &lt;property name="severity" value="ignore"/&gt;
 61  
  *    &lt;property name="tagSeverity" value="warning"/&gt;
 62  
  * &lt;/module&gt;
 63  
  * </pre>
 64  
  *
 65  
  * @author Daniel Grenner
 66  
  */
 67  
 @StatelessCheck
 68  22
 public class WriteTagCheck
 69  
     extends AbstractCheck {
 70  
 
 71  
     /**
 72  
      * A key is pointing to the warning message text in "messages.properties"
 73  
      * file.
 74  
      */
 75  
     public static final String MSG_MISSING_TAG = "type.missingTag";
 76  
 
 77  
     /**
 78  
      * A key is pointing to the warning message text in "messages.properties"
 79  
      * file.
 80  
      */
 81  
     public static final String MSG_WRITE_TAG = "javadoc.writeTag";
 82  
 
 83  
     /**
 84  
      * A key is pointing to the warning message text in "messages.properties"
 85  
      * file.
 86  
      */
 87  
     public static final String MSG_TAG_FORMAT = "type.tagFormat";
 88  
 
 89  
     /** Compiled regexp to match tag. **/
 90  
     private Pattern tagRegExp;
 91  
     /** Compiled regexp to match tag content. **/
 92  
     private Pattern tagFormat;
 93  
 
 94  
     /** Regexp to match tag. */
 95  
     private String tag;
 96  
     /** The severity level of found tag reports. */
 97  22
     private SeverityLevel tagSeverity = SeverityLevel.INFO;
 98  
 
 99  
     /**
 100  
      * Sets the tag to check.
 101  
      * @param tag tag to check
 102  
      */
 103  
     public void setTag(String tag) {
 104  15
         this.tag = tag;
 105  15
         tagRegExp = CommonUtils.createPattern(tag + "\\s*(.*$)");
 106  15
     }
 107  
 
 108  
     /**
 109  
      * Set the tag format.
 110  
      * @param pattern a {@code String} value
 111  
      */
 112  
     public void setTagFormat(Pattern pattern) {
 113  13
         tagFormat = pattern;
 114  13
     }
 115  
 
 116  
     /**
 117  
      * Sets the tag severity level.
 118  
      *
 119  
      * @param severity  The new severity level
 120  
      * @see SeverityLevel
 121  
      */
 122  
     public final void setTagSeverity(SeverityLevel severity) {
 123  3
         tagSeverity = severity;
 124  3
     }
 125  
 
 126  
     @Override
 127  
     public int[] getDefaultTokens() {
 128  20
         return new int[] {TokenTypes.INTERFACE_DEF,
 129  
                           TokenTypes.CLASS_DEF,
 130  
                           TokenTypes.ENUM_DEF,
 131  
                           TokenTypes.ANNOTATION_DEF,
 132  
         };
 133  
     }
 134  
 
 135  
     @Override
 136  
     public int[] getAcceptableTokens() {
 137  7
         return new int[] {TokenTypes.INTERFACE_DEF,
 138  
                           TokenTypes.CLASS_DEF,
 139  
                           TokenTypes.ENUM_DEF,
 140  
                           TokenTypes.ANNOTATION_DEF,
 141  
                           TokenTypes.METHOD_DEF,
 142  
                           TokenTypes.CTOR_DEF,
 143  
                           TokenTypes.ENUM_CONSTANT_DEF,
 144  
                           TokenTypes.ANNOTATION_FIELD_DEF,
 145  
         };
 146  
     }
 147  
 
 148  
     @Override
 149  
     public int[] getRequiredTokens() {
 150  25
         return CommonUtils.EMPTY_INT_ARRAY;
 151  
     }
 152  
 
 153  
     @Override
 154  
     public void visitToken(DetailAST ast) {
 155  20
         final FileContents contents = getFileContents();
 156  20
         final int lineNo = ast.getLineNo();
 157  20
         final TextBlock cmt =
 158  20
             contents.getJavadocBefore(lineNo);
 159  20
         if (cmt == null) {
 160  1
             log(lineNo, MSG_MISSING_TAG, tag);
 161  
         }
 162  
         else {
 163  19
             checkTag(lineNo, cmt.getText());
 164  
         }
 165  20
     }
 166  
 
 167  
     /**
 168  
      * Verifies that a type definition has a required tag.
 169  
      * @param lineNo the line number for the type definition.
 170  
      * @param comment the Javadoc comment for the type definition.
 171  
      */
 172  
     private void checkTag(int lineNo, String... comment) {
 173  19
         if (tagRegExp != null) {
 174  18
             int tagCount = 0;
 175  127
             for (int i = 0; i < comment.length; i++) {
 176  109
                 final String commentValue = comment[i];
 177  109
                 final Matcher matcher = tagRegExp.matcher(commentValue);
 178  109
                 if (matcher.find()) {
 179  16
                     tagCount += 1;
 180  16
                     final int contentStart = matcher.start(1);
 181  16
                     final String content = commentValue.substring(contentStart);
 182  16
                     if (tagFormat == null || tagFormat.matcher(content).find()) {
 183  15
                         logTag(lineNo + i - comment.length, tag, content);
 184  
                     }
 185  
                     else {
 186  1
                         log(lineNo + i - comment.length, MSG_TAG_FORMAT, tag, tagFormat.pattern());
 187  
                     }
 188  
                 }
 189  
             }
 190  18
             if (tagCount == 0) {
 191  3
                 log(lineNo, MSG_MISSING_TAG, tag);
 192  
             }
 193  
         }
 194  19
     }
 195  
 
 196  
     /**
 197  
      * Log a message.
 198  
      *
 199  
      * @param line the line number where the error was found
 200  
      * @param tagName the javadoc tag to be logged
 201  
      * @param tagValue the contents of the tag
 202  
      *
 203  
      * @see java.text.MessageFormat
 204  
      */
 205  
     private void logTag(int line, String tagName, String tagValue) {
 206  15
         final String originalSeverity = getSeverity();
 207  15
         setSeverity(tagSeverity.getName());
 208  
 
 209  15
         log(line, MSG_WRITE_TAG, tagName, tagValue);
 210  
 
 211  15
         setSeverity(originalSeverity);
 212  15
     }
 213  
 }