Coverage Report - com.puppycrawl.tools.checkstyle.checks.javadoc.WriteTagCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
WriteTagCheck
91%
42/46
100%
14/14
2.5
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 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  
 package com.puppycrawl.tools.checkstyle.checks.javadoc;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.Check;
 22  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 23  
 import com.puppycrawl.tools.checkstyle.api.FileContents;
 24  
 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
 25  
 import com.puppycrawl.tools.checkstyle.api.TextBlock;
 26  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 27  
 import com.puppycrawl.tools.checkstyle.api.Utils;
 28  
 import java.util.regex.Matcher;
 29  
 import java.util.regex.Pattern;
 30  
 import java.util.regex.PatternSyntaxException;
 31  
 import org.apache.commons.beanutils.ConversionException;
 32  
 
 33  
 /**
 34  
  * <p>
 35  
  * Outputs a JavaDoc tag as information. Can be used e.g. with the stylesheets
 36  
  * that sort the report by author name.
 37  
  * To define the format for a tag, set property tagFormat to a
 38  
  * regular expression.
 39  
  * This check uses two different severity levels. The normal one is used for
 40  
  * reporting when the tag is missing. The additional one (tagSeverity) is used
 41  
  * for the level of reporting when the tag exists. The default value for
 42  
  * tagSeverity is info.
 43  
  * </p>
 44  
  * <p> An example of how to configure the check for printing author name is:
 45  
  *</p>
 46  
  * <pre>
 47  
  * &lt;module name="WriteTag"&gt;
 48  
  *    &lt;property name="tag" value="@author"/&gt;
 49  
  *    &lt;property name="tagFormat" value="\S"/&gt;
 50  
  * &lt;/module&gt;
 51  
  * </pre>
 52  
  * <p> An example of how to configure the check to print warnings if an
 53  
  * "@incomplete" tag is found, and not print anything if it is not found:
 54  
  *</p>
 55  
  * <pre>
 56  
  * &lt;module name="WriteTag"&gt;
 57  
  *    &lt;property name="tag" value="@incomplete"/&gt;
 58  
  *    &lt;property name="tagFormat" value="\S"/&gt;
 59  
  *    &lt;property name="severity" value="ignore"/&gt;
 60  
  *    &lt;property name="tagSeverity" value="warning"/&gt;
 61  
  * &lt;/module&gt;
 62  
  * </pre>
 63  
  *
 64  
  * @author Daniel Grenner
 65  
  * @version 1.0
 66  
  */
 67  13
 public class WriteTagCheck
 68  
     extends Check
 69  
 {
 70  
     /** compiled regexp to match tag **/
 71  
     private Pattern mTagRE;
 72  
     /** compiled regexp to match tag content **/
 73  
     private Pattern mTagFormatRE;
 74  
 
 75  
     /** regexp to match tag */
 76  
     private String mTag;
 77  
     /** regexp to match tag content */
 78  
     private String mTagFormat;
 79  
     /** the severity level of found tag reports */
 80  13
     private SeverityLevel mTagSeverityLevel = SeverityLevel.INFO;
 81  
 
 82  
     /**
 83  
      * Sets the tag to check.
 84  
      * @param aTag tag to check
 85  
      * @throws ConversionException If the tag is not a valid regular exception.
 86  
      */
 87  
     public void setTag(String aTag)
 88  
         throws ConversionException
 89  
     {
 90  
         try {
 91  12
             mTag = aTag;
 92  12
             mTagRE = Utils.getPattern(aTag + "\\s*(.*$)");
 93  
         }
 94  0
         catch (final PatternSyntaxException e) {
 95  0
             throw new ConversionException("unable to parse " + aTag, e);
 96  12
         }
 97  12
     }
 98  
 
 99  
     /**
 100  
      * Set the tag format.
 101  
      * @param aFormat a <code>String</code> value
 102  
      * @throws ConversionException unable to parse aFormat
 103  
      */
 104  
     public void setTagFormat(String aFormat)
 105  
         throws ConversionException
 106  
     {
 107  
         try {
 108  10
             mTagFormat = aFormat;
 109  10
             mTagFormatRE = Utils.getPattern(aFormat);
 110  
         }
 111  0
         catch (final PatternSyntaxException e) {
 112  0
             throw new ConversionException("unable to parse " + aFormat, e);
 113  10
         }
 114  10
     }
 115  
 
 116  
     /**
 117  
      * Sets the tag severity level.  The string should be one of the names
 118  
      * defined in the <code>SeverityLevel</code> class.
 119  
      *
 120  
      * @param aSeverity  The new severity level
 121  
      * @see SeverityLevel
 122  
      */
 123  
     public final void setTagSeverity(String aSeverity)
 124  
     {
 125  2
         mTagSeverityLevel = SeverityLevel.getInstance(aSeverity);
 126  2
     }
 127  
 
 128  
     @Override
 129  
     public int[] getDefaultTokens()
 130  
     {
 131  11
         return new int[] {TokenTypes.INTERFACE_DEF,
 132  
                           TokenTypes.CLASS_DEF,
 133  
                           TokenTypes.ENUM_DEF,
 134  
                           TokenTypes.ANNOTATION_DEF,
 135  
         };
 136  
     }
 137  
 
 138  
     @Override
 139  
     public int[] getAcceptableTokens()
 140  
     {
 141  2
         return new int[] {TokenTypes.INTERFACE_DEF,
 142  
                           TokenTypes.CLASS_DEF,
 143  
                           TokenTypes.ENUM_DEF,
 144  
                           TokenTypes.ANNOTATION_DEF,
 145  
                           TokenTypes.METHOD_DEF,
 146  
                           TokenTypes.CTOR_DEF,
 147  
                           TokenTypes.ENUM_CONSTANT_DEF,
 148  
                           TokenTypes.ANNOTATION_FIELD_DEF,
 149  
         };
 150  
     }
 151  
 
 152  
     @Override
 153  
     public void visitToken(DetailAST aAST)
 154  
     {
 155  19
         final FileContents contents = getFileContents();
 156  19
         final int lineNo = aAST.getLineNo();
 157  19
         final TextBlock cmt =
 158  
             contents.getJavadocBefore(lineNo);
 159  19
         if (cmt == null) {
 160  1
             log(lineNo, "type.missingTag", mTag);
 161  
         }
 162  
         else {
 163  18
             checkTag(lineNo, cmt.getText(), mTag, mTagRE, mTagFormatRE,
 164  
                 mTagFormat);
 165  
         }
 166  19
     }
 167  
 
 168  
     /**
 169  
      * Verifies that a type definition has a required tag.
 170  
      * @param aLineNo the line number for the type definition.
 171  
      * @param aComment the Javadoc comment for the type definition.
 172  
      * @param aTag the required tag name.
 173  
      * @param aTagRE regexp for the full tag.
 174  
      * @param aFormatRE regexp for the tag value.
 175  
      * @param aFormat pattern for the tag value.
 176  
      */
 177  
     private void checkTag(
 178  
             int aLineNo,
 179  
             String[] aComment,
 180  
             String aTag,
 181  
             Pattern aTagRE,
 182  
             Pattern aFormatRE,
 183  
             String aFormat)
 184  
     {
 185  18
         if (aTagRE == null) {
 186  1
             return;
 187  
         }
 188  
 
 189  17
         int tagCount = 0;
 190  123
         for (int i = 0; i < aComment.length; i++) {
 191  106
             final String s = aComment[i];
 192  106
             final Matcher matcher = aTagRE.matcher(s);
 193  106
             if (matcher.find()) {
 194  15
                 tagCount += 1;
 195  15
                 final int contentStart = matcher.start(1);
 196  15
                 final String content = s.substring(contentStart);
 197  15
                 if ((aFormatRE != null) && !aFormatRE.matcher(content).find()) {
 198  1
                     log(aLineNo + i - aComment.length, "type.tagFormat", aTag,
 199  
                         aFormat);
 200  
                 }
 201  
                 else {
 202  14
                     logTag(aLineNo + i - aComment.length, aTag, content);
 203  
                 }
 204  
 
 205  
             }
 206  
         }
 207  17
         if (tagCount == 0) {
 208  3
             log(aLineNo, "type.missingTag", aTag);
 209  
         }
 210  
 
 211  17
     }
 212  
 
 213  
 
 214  
     /**
 215  
      * Log a message.
 216  
      *
 217  
      * @param aLine the line number where the error was found
 218  
      * @param aTag the javdoc tag to be logged
 219  
      * @param aTagValue the contents of the tag
 220  
      *
 221  
      * @see java.text.MessageFormat
 222  
      */
 223  
     protected final void logTag(int aLine, String aTag, String aTagValue)
 224  
     {
 225  14
         final String originalSeverity = getSeverity();
 226  14
         setSeverity(mTagSeverityLevel.getName());
 227  
 
 228  14
         log(aLine, "javadoc.writeTag", aTag, aTagValue);
 229  
 
 230  14
         setSeverity(originalSeverity);
 231  14
     }
 232  
 }