KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > TrailingCommentCheck


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 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;
20
21 import com.puppycrawl.tools.checkstyle.api.DetailAST;
22 import com.puppycrawl.tools.checkstyle.api.TextBlock;
23 import com.puppycrawl.tools.checkstyle.api.Utils;
24
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.regex.Pattern JavaDoc;
31 import java.util.regex.PatternSyntaxException JavaDoc;
32
33 import org.apache.commons.beanutils.ConversionException;
34
35 /**
36  * <p>
37  * The check to ensure that requires that comments be the only thing on a line.
38  * For the case of // comments that means that the only thing that should
39  * precede it is whitespace.
40  * It doesn't check comments if they do not end line, i.e. it accept
41  * the following:
42  * <code>Thread.sleep( 10 &lt;some comment here&gt; );</code>
43  * Format property is intended to deal with the "} // while" example.
44  * </p>
45  * <p>
46  * Rationale: Steve McConnel in &quot;Code Complete&quot; suggests that endline
47  * comments are a bad practice. An end line comment would
48  * be one that is on the same line as actual code. For example:
49  * <pre>
50  * a = b + c; // Some insightful comment
51  * d = e / f; // Another comment for this line
52  * </pre>
53  * Quoting &quot;Code Complete&quot; for the justfication:
54  * <ul>
55  * <li>
56  * &quot;The comments have to be aligned so that they do not
57  * interfere with the visual structure of the code. If you don't
58  * align them neatly, they'll make your listing look like it's been
59  * through a washing machine.&quot;
60  * </li>
61  * <li>
62  * &quot;Endline comments tend to be hard to format...It takes time
63  * to align them. Such time is not spent learning more about
64  * the code; it's dedicated solely to the tedious task of
65  * pressing the spacebar or tab key.&quot;
66  * </li>
67  * <li>
68  * &quot;Endline comments are also hard to maintain. If the code on
69  * any line containing an endline comment grows, it bumps the
70  * comment farther out, and all the other endline comments will
71  * have to bumped out to match. Styles that are hard to
72  * maintain aren't maintained....&quot;
73  * </li>
74  * <li>
75  * &quot;Endline comments also tend to be cryptic. The right side of
76  * the line doesn't offer much room and the desire to keep the
77  * comment on one line means the comment must be short.
78  * Work then goes into making the line as short as possible
79  * instead of as clear as possible. The comment usually ends
80  * up as cryptic as possible....&quot;
81  * </li>
82  * <li>
83  * &quot;A systemic problem with endline comments is that it's hard
84  * to write a meaningful comment for one line of code. Most
85  * endline comments just repeat the line of code, which hurts
86  * more than it helps.&quot;
87  * </li>
88  * </ul>
89  * His comments on being hard to maintain when the size of
90  * the line changes are even more important in the age of
91  * automated refactorings.
92  * </p>
93  * <p>
94  * To configure the check so it enforces only comment on a line:
95  * <pre>
96  * &lt;module name=&quot;TrailingComment&quot;&gt;
97  * &lt;property name=&quot;format&quot; value=&quot;^\\s*$&quot;/&gt;
98  * &lt;/module&gt;
99  * </pre>
100  * </p>
101  * @author o_sukhodolsky
102  */

103 public class TrailingCommentCheck extends AbstractFormatCheck
104 {
105     /** default format for allowed blank line. */
106     private static final String JavaDoc DEFAULT_FORMAT = "^[\\s\\}\\);]*$";
107
108     /** pattern for legal trailing comment. */
109     private Pattern JavaDoc mLegalComment;
110
111     /**
112      * Sets patter for legal trailing comments.
113      * @param aFormat format to set.
114      * @throws ConversionException unable to parse a given format.
115      */

116     public void setLegalComment(final String JavaDoc aFormat)
117         throws ConversionException
118     {
119         try {
120             mLegalComment = Utils.getPattern(aFormat);
121         }
122         catch (final PatternSyntaxException JavaDoc e) {
123             throw new ConversionException("unable to parse " + aFormat, e);
124         }
125     }
126     /**
127      * Creates new instance of the check.
128      * @throws ConversionException unable to parse DEFAULT_FORMAT.
129      */

130     public TrailingCommentCheck() throws ConversionException
131     {
132         super(DEFAULT_FORMAT);
133     }
134
135     /** {@inheritDoc} */
136     public int[] getDefaultTokens()
137     {
138         return new int[0];
139     }
140
141     /** {@inheritDoc} */
142     public void visitToken(DetailAST aAST)
143     {
144         throw new IllegalStateException JavaDoc("visitToken() shouldn't be called.");
145     }
146
147     /** {@inheritDoc} */
148     public void beginTree(DetailAST aRootAST)
149     {
150         final Pattern JavaDoc blankLinePattern = getRegexp();
151         final Map JavaDoc cppComments = getFileContents().getCppComments();
152         final Map JavaDoc cComments = getFileContents().getCComments();
153         final Set JavaDoc lines = new HashSet JavaDoc();
154         lines.addAll(cppComments.keySet());
155         lines.addAll(cComments.keySet());
156
157         final Iterator JavaDoc linesIter = lines.iterator();
158         while (linesIter.hasNext()) {
159             final Integer JavaDoc lineNo = (Integer JavaDoc) linesIter.next();
160
161             final String JavaDoc line = getLines()[lineNo.intValue() - 1];
162             String JavaDoc lineBefore = "";
163             TextBlock comment = null;
164             if (cppComments.containsKey(lineNo)) {
165                 comment = (TextBlock) cppComments.get(lineNo);
166                 lineBefore = line.substring(0, comment.getStartColNo());
167             }
168             else if (cComments.containsKey(lineNo)) {
169                 final List JavaDoc commentList = (List JavaDoc) cComments.get(lineNo);
170                 comment = (TextBlock) commentList.get(commentList.size() - 1);
171                 lineBefore = line.substring(0, comment.getStartColNo());
172                 if (comment.getText().length == 1) {
173                     final String JavaDoc lineAfter =
174                         line.substring(comment.getEndColNo() + 1).trim();
175                     if (!"".equals(lineAfter)) {
176                         // do not check comment which doesn't end line
177
continue;
178                     }
179                 }
180             }
181             if ((comment != null)
182                 && !blankLinePattern.matcher(lineBefore).find()
183                 && !isLegalComment(comment))
184             {
185                 log(lineNo.intValue(), "trailing.comments");
186             }
187         }
188     }
189
190     /**
191      * Checks if given comment is legal (single-line and matches to the
192      * pattern).
193      * @param aComment comment to check.
194      * @return true if the comment if legal.
195      */

196     private boolean isLegalComment(final TextBlock aComment)
197     {
198         if (mLegalComment == null) {
199             return false;
200         }
201         // multi-line comment can not be legal
202
if (aComment.getStartLineNo() != aComment.getEndLineNo()) {
203             return false;
204         }
205         String JavaDoc commentText = aComment.getText()[0];
206         // remove chars which start comment
207
commentText = commentText.substring(2);
208         // if this is a C-style comment we need to remove its end
209
if (commentText.endsWith("*/")) {
210             commentText = commentText.substring(0, commentText.length() - 2);
211         }
212         commentText = commentText.trim();
213         return mLegalComment.matcher(commentText).find();
214     }
215 }
216
Popular Tags