Source code: com/puppycrawl/tools/checkstyle/checks/JavadocTypeCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2002 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 org.apache.commons.beanutils.ConversionException;
22 import org.apache.regexp.RE;
23 import org.apache.regexp.RESyntaxException;
24
25 import com.puppycrawl.tools.checkstyle.api.Check;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.FileContents;
28 import com.puppycrawl.tools.checkstyle.api.Scope;
29 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
30 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31 import com.puppycrawl.tools.checkstyle.api.Utils;
32
33 /**
34 * <p>
35 * Checks the Javadoc of a type.
36 * By default, does not check for author or version tags.
37 * The scope to verify is specified using the {@link Scope} class and
38 * defaults to {@link Scope#PRIVATE}. To verify another scope,
39 * set property scope to one of the {@link Scope} constants.
40 * To define the format for an author tag or a version tag,
41 * set property authorFormat or versionFormat respectively to a
42 * <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">
43 * regular expression</a>.
44 * </p>
45 * <p>
46 * An example of how to configure the check is:
47 * </p>
48 * <pre>
49 * <module name="JavadocType"/>
50 * </pre>
51 * <p> An example of how to configure the check for the
52 * {@link Scope#PUBLIC} scope is:
53 *</p>
54 * <pre>
55 * <module name="JavadocType">
56 * <property name="scope" value="public"/>
57 * </module>
58 * </pre>
59 * <p> An example of how to configure the check for an author tag
60 * and a version tag is:
61 *</p>
62 * <pre>
63 * <module name="JavadocType">
64 * <property name="authorFormat" value="\S"/>
65 * <property name="versionFormat" value="\S"/>
66 * </module>
67 * </pre>
68 * <p> An example of how to configure the check for a
69 * CVS revision version tag is:
70 *</p>
71 * <pre>
72 * <module name="JavadocType">
73 * <property name="versionFormat" value="\$Revision.*\$"/>
74 * </module>
75 * </pre>
76 *
77
78 * @author <a href="mailto:checkstyle@puppycrawl.com">Oliver Burn</a>
79 * @version 1.0
80 */
81 public class JavadocTypeCheck
82 extends Check
83 {
84 /** the scope to check for */
85 private Scope mScope = Scope.PRIVATE;
86 /** compiled regexp to match author tag **/
87 private RE mAuthorTagRE = null;
88 /** compiled regexp to match author tag content **/
89 private RE mAuthorFormatRE = null;
90 /** compiled regexp to match version tag **/
91 private RE mVersionTagRE = null;
92 /** compiled regexp to match version tag content **/
93 private RE mVersionFormatRE = null;
94 /** regexp to match author tag content */
95 private String mAuthorFormat;
96 /** regexp to match version tag content */
97 private String mVersionFormat;
98
99 /**
100 * Sets the scope to check.
101 * @param aFrom string to set scope from
102 */
103 public void setScope(String aFrom)
104 {
105 mScope = Scope.getInstance(aFrom);
106 }
107
108 /**
109 * Set the author tag pattern.
110 * @param aFormat a <code>String</code> value
111 * @throws ConversionException unable to parse aFormat
112 */
113 public void setAuthorFormat(String aFormat)
114 throws ConversionException
115 {
116 try {
117 mAuthorTagRE = Utils.getRE("@author\\s+(.*$)");
118 mAuthorFormat = aFormat;
119 mAuthorFormatRE = Utils.getRE(aFormat);
120 }
121 catch (RESyntaxException e) {
122 throw new ConversionException("unable to parse " + aFormat, e);
123 }
124 }
125
126 /**
127 * Set the version format pattern.
128 * @param aFormat a <code>String</code> value
129 * @throws ConversionException unable to parse aFormat
130 */
131 public void setVersionFormat(String aFormat)
132 throws ConversionException
133 {
134 try {
135 mVersionTagRE = Utils.getRE("@version\\s+(.*$)");
136 mVersionFormat = aFormat;
137 mVersionFormatRE = Utils.getRE(aFormat);
138 }
139 catch (RESyntaxException e) {
140 throw new ConversionException("unable to parse " + aFormat, e);
141 }
142
143 }
144
145 /** @see com.puppycrawl.tools.checkstyle.api.Check */
146 public int[] getDefaultTokens()
147 {
148 return new int[] {TokenTypes.INTERFACE_DEF, TokenTypes.CLASS_DEF};
149 }
150
151 /** @see com.puppycrawl.tools.checkstyle.api.Check */
152 public void visitToken(DetailAST aAST)
153 {
154 final DetailAST mods = aAST.findFirstToken(TokenTypes.MODIFIERS);
155 final Scope declaredScope = ScopeUtils.getScopeFromMods(mods);
156 final Scope typeScope =
157 ScopeUtils.inInterfaceBlock(aAST) ? Scope.PUBLIC : declaredScope;
158 if (typeScope.isIn(mScope)) {
159 final Scope surroundingScope = ScopeUtils.getSurroundingScope(aAST);
160 if ((surroundingScope == null) || surroundingScope.isIn(mScope)) {
161 final FileContents contents = getFileContents();
162 final int lineNo = aAST.getLineNo();
163 final String[] cmt =
164 contents.getJavadocBefore(lineNo);
165 if (cmt == null) {
166 log(lineNo, "javadoc.missing");
167 }
168 else if (ScopeUtils.isOuterMostType(aAST)) {
169 // don't check author/version for inner classes
170 checkTag(lineNo, cmt, "@author",
171 mAuthorTagRE, mAuthorFormatRE, mAuthorFormat);
172 checkTag(lineNo, cmt, "@version",
173 mVersionTagRE, mVersionFormatRE, mVersionFormat);
174 }
175 }
176 }
177 }
178
179 /**
180 * Verifies that a type definition has a required tag.
181 * @param aLineNo the line number for the type definition.
182 * @param aCmt the Javadoc comment for the type definition.
183 * @param aTag the required tag name.
184 * @param aTagRE regexp for the full tag.
185 * @param aFormatRE regexp for the tag value.
186 * @param aFormat pattern for the tag value.
187 */
188 private void checkTag(
189 int aLineNo,
190 String[] aCmt,
191 String aTag,
192 RE aTagRE,
193 RE aFormatRE,
194 String aFormat)
195 {
196 if (aTagRE == null) {
197 return;
198 }
199
200 int tagCount = 0;
201 for (int i = 0; i < aCmt.length; i++) {
202 final String s = aCmt[i];
203 if (aTagRE.match(s)) {
204 tagCount += 1;
205 final int contentStart = aTagRE.getParenStart(1);
206 final String content = s.substring(contentStart);
207 if (!aFormatRE.match(content)) {
208 log(aLineNo, "type.tagFormat", aTag, aFormat);
209 }
210
211 }
212 }
213 if (tagCount == 0) {
214 log(aLineNo, "type.missingTag", aTag);
215 }
216
217 }
218
219 }