KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > javadoc > JavadocTypeCheck


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.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.Scope;
25 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
26 import com.puppycrawl.tools.checkstyle.api.TextBlock;
27 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28 import com.puppycrawl.tools.checkstyle.api.Utils;
29 import com.puppycrawl.tools.checkstyle.checks.CheckUtils;
30 import org.apache.commons.beanutils.ConversionException;
31
32 import java.util.Vector JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.regex.Matcher JavaDoc;
36 import java.util.regex.Pattern JavaDoc;
37 import java.util.regex.PatternSyntaxException JavaDoc;
38
39 /**
40  * Checks the Javadoc of a type.
41  *
42  * @author Oliver Burn
43  * @author Michael Tamm
44  * @version 1.1
45  */

46 public class JavadocTypeCheck
47     extends Check
48 {
49     /** the scope to check for */
50     private Scope mScope = Scope.PRIVATE;
51     /** the visibility scope where Javadoc comments shouldn't be checked **/
52     private Scope mExcludeScope;
53     /** compiled regexp to match author tag content **/
54     private Pattern JavaDoc mAuthorFormatPattern;
55     /** compiled regexp to match version tag content **/
56     private Pattern JavaDoc mVersionFormatPattern;
57     /** regexp to match author tag content */
58     private String JavaDoc mAuthorFormat;
59     /** regexp to match version tag content */
60     private String JavaDoc mVersionFormat;
61     /**
62      * controls whether to ignore errors when a method has type parameters but
63      * does not have matching param tags in the javadoc. Defaults to false.
64      */

65     private boolean mAllowMissingParamTags;
66
67     /**
68      * Sets the scope to check.
69      * @param aFrom string to set scope from
70      */

71     public void setScope(String JavaDoc aFrom)
72     {
73         mScope = Scope.getInstance(aFrom);
74     }
75
76     /**
77      * Set the excludeScope.
78      * @param aScope a <code>String</code> value
79      */

80     public void setExcludeScope(String JavaDoc aScope)
81     {
82         mExcludeScope = Scope.getInstance(aScope);
83     }
84
85     /**
86      * Set the author tag pattern.
87      * @param aFormat a <code>String</code> value
88      * @throws ConversionException unable to parse aFormat
89      */

90     public void setAuthorFormat(String JavaDoc aFormat)
91         throws ConversionException
92     {
93         try {
94             mAuthorFormat = aFormat;
95             mAuthorFormatPattern = Utils.getPattern(aFormat);
96         }
97         catch (final PatternSyntaxException JavaDoc e) {
98             throw new ConversionException("unable to parse " + aFormat, e);
99         }
100     }
101
102     /**
103      * Set the version format pattern.
104      * @param aFormat a <code>String</code> value
105      * @throws ConversionException unable to parse aFormat
106      */

107     public void setVersionFormat(String JavaDoc aFormat)
108         throws ConversionException
109     {
110         try {
111             mVersionFormat = aFormat;
112             mVersionFormatPattern = Utils.getPattern(aFormat);
113         }
114         catch (final PatternSyntaxException JavaDoc e) {
115             throw new ConversionException("unable to parse " + aFormat, e);
116         }
117
118     }
119
120     /**
121      * Controls whether to allow a type which has type parameters to
122      * omit matching param tags in the javadoc. Defaults to false.
123      *
124      * @param aFlag a <code>Boolean</code> value
125      */

126     public void setAllowMissingParamTags(boolean aFlag)
127     {
128         mAllowMissingParamTags = aFlag;
129     }
130
131     /** {@inheritDoc} */
132     public int[] getDefaultTokens()
133     {
134         return new int[] {
135             TokenTypes.INTERFACE_DEF,
136             TokenTypes.CLASS_DEF,
137             TokenTypes.ENUM_DEF,
138             TokenTypes.ANNOTATION_DEF,
139         };
140     }
141
142     /** {@inheritDoc} */
143     public void visitToken(DetailAST aAST)
144     {
145         if (shouldCheck(aAST)) {
146             final FileContents contents = getFileContents();
147             final int lineNo = aAST.getLineNo();
148             final TextBlock cmt = contents.getJavadocBefore(lineNo);
149             if (cmt == null) {
150                 log(lineNo, "javadoc.missing");
151             }
152             else if (ScopeUtils.isOuterMostType(aAST)) {
153                 // don't check author/version for inner classes
154
final Vector JavaDoc tags = getJavadocTags(cmt);
155                 checkTag(lineNo, tags, "author",
156                          mAuthorFormatPattern, mAuthorFormat);
157                 checkTag(lineNo, tags, "version",
158                          mVersionFormatPattern, mVersionFormat);
159
160                 final List JavaDoc typeParamNames =
161                     CheckUtils.getTypeParameterNames(aAST);
162
163                 if (!mAllowMissingParamTags) {
164                     //Check type parameters that should exist, do
165
for (final Iterator JavaDoc typeParamNameIt =
166                              typeParamNames.iterator();
167                          typeParamNameIt.hasNext();)
168                     {
169                         checkTypeParamTag(
170                             lineNo, tags, (String JavaDoc) typeParamNameIt.next());
171                     }
172                 }
173
174                 checkUnusedTypeParamTags(tags, typeParamNames);
175             }
176         }
177     }
178
179     /**
180      * Whether we should check this node.
181      * @param aAST a given node.
182      * @return whether we should check a given node.
183      */

184     private boolean shouldCheck(final DetailAST aAST)
185     {
186         final DetailAST mods = aAST.findFirstToken(TokenTypes.MODIFIERS);
187         final Scope declaredScope = ScopeUtils.getScopeFromMods(mods);
188         final Scope scope =
189             ScopeUtils.inInterfaceOrAnnotationBlock(aAST)
190                 ? Scope.PUBLIC : declaredScope;
191         final Scope surroundingScope = ScopeUtils.getSurroundingScope(aAST);
192
193         return scope.isIn(mScope)
194             && ((surroundingScope == null) || surroundingScope.isIn(mScope))
195             && ((mExcludeScope == null)
196                 || !scope.isIn(mExcludeScope)
197                 || ((surroundingScope != null)
198                 && !surroundingScope.isIn(mExcludeScope)));
199     }
200
201     /**
202      * Gets all standalone tags from a given javadoc.
203      * @param aCmt teh Javadoc comment to process.
204      * @return all standalone tags from the given javadoc.
205      */

206     private Vector JavaDoc getJavadocTags(TextBlock aCmt)
207     {
208         final String JavaDoc[] text = aCmt.getText();
209         final Vector JavaDoc tags = new Vector JavaDoc();
210         Pattern JavaDoc tagPattern = Utils.getPattern("/\\*{2,}\\s*@(\\p{Alpha}+)\\s");
211         for (int i = 0; i < text.length; i++) {
212             final String JavaDoc s = text[i];
213             final Matcher JavaDoc tagMatcher = tagPattern.matcher(s);
214             if (tagMatcher.find()) {
215                 final String JavaDoc tagName = tagMatcher.group(1);
216                 String JavaDoc content = s.substring(tagMatcher.end(1));
217                 if (content.endsWith("*/")) {
218                     content = content.substring(0, content.length() - 2);
219                 }
220                 int col = tagMatcher.start(1) - 1;
221                 if (i == 0) {
222                     col += aCmt.getStartColNo();
223                 }
224                 tags.add(new JavadocTag(aCmt.getStartLineNo() + i, col,
225                                         tagName, content.trim()));
226             }
227             tagPattern = Utils.getPattern("^\\s*\\**\\s*@(\\p{Alpha}+)\\s");
228         }
229         return tags;
230     }
231
232     /**
233      * Verifies that a type definition has a required tag.
234      * @param aLineNo the line number for the type definition.
235      * @param aTags tags from the Javadoc comment for the type definition.
236      * @param aTag the required tag name.
237      * @param aFormatPattern regexp for the tag value.
238      * @param aFormat pattern for the tag value.
239      */

240     private void checkTag(int aLineNo, Vector JavaDoc aTags, String JavaDoc aTag,
241                           Pattern JavaDoc aFormatPattern, String JavaDoc aFormat)
242     {
243         if (aFormatPattern == null) {
244             return;
245         }
246
247         int tagCount = 0;
248         for (int i = aTags.size() - 1; i >= 0; i--) {
249             final JavadocTag tag = (JavadocTag) aTags.get(i);
250             if (tag.getTag().equals(aTag)) {
251                 tagCount++;
252                 if (!aFormatPattern.matcher(tag.getArg1()).find()) {
253                     log(aLineNo, "type.tagFormat", "@" + aTag, aFormat);
254                 }
255             }
256         }
257         if (tagCount == 0) {
258             log(aLineNo, "type.missingTag", "@" + aTag);
259         }
260     }
261
262     /**
263      * Verifies that a type definition has the specified param tag for
264      * the specified type parameter name.
265      * @param aLineNo the line number for the type definition.
266      * @param aTags tags from the Javadoc comment for the type definition.
267      * @param aTypeParamName the name of the type parameter
268      */

269     private void checkTypeParamTag(
270         final int aLineNo, final Vector JavaDoc aTags, final String JavaDoc aTypeParamName)
271     {
272         boolean found = false;
273         for (int i = aTags.size() - 1; i >= 0; i--) {
274             final JavadocTag tag = (JavadocTag) aTags.get(i);
275             if (tag.getTag().equals("param")
276                 && (tag.getArg1() != null)
277                 && (tag.getArg1().indexOf("<" + aTypeParamName + ">") == 0))
278             {
279                 found = true;
280             }
281         }
282         if (!found) {
283             log(aLineNo, "type.missingTag", "@param <" + aTypeParamName + ">");
284         }
285     }
286
287     /**
288      * Checks for unused param tags for type parameters.
289      * @param aTags tags from the Javadoc comment for the type definition.
290      * @param aTypeParamNames names of type parameters
291      */

292     private void checkUnusedTypeParamTags(
293         final Vector JavaDoc aTags,
294         final List JavaDoc aTypeParamNames)
295     {
296         final Pattern JavaDoc pattern = Utils.getPattern("\\s*<([^>]+)>.*");
297         for (int i = aTags.size() - 1; i >= 0; i--) {
298             final JavadocTag tag = (JavadocTag) aTags.get(i);
299             if (tag.getTag().equals("param")) {
300
301                 if (tag.getArg1() != null) {
302
303                     final Matcher JavaDoc matcher = pattern.matcher(tag.getArg1());
304                     String JavaDoc typeParamName = null;
305
306                     if (matcher.matches()) {
307                         typeParamName = matcher.group(1).trim();
308                         if (!aTypeParamNames.contains(typeParamName)) {
309                             log(tag.getLineNo(), tag.getColumnNo(),
310                                 "javadoc.unusedTag",
311                                 "@param", "<" + typeParamName + ">");
312                         }
313                     }
314                     else {
315                         log(tag.getLineNo(), tag.getColumnNo(),
316                             "javadoc.unusedTagGeneral");
317                     }
318                 }
319                 else {
320                     log(tag.getLineNo(), tag.getColumnNo(),
321                         "javadoc.unusedTagGeneral");
322                 }
323             }
324         }
325     }
326 }
327
Popular Tags