1 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 ; 33 import java.util.List ; 34 import java.util.Iterator ; 35 import java.util.regex.Matcher ; 36 import java.util.regex.Pattern ; 37 import java.util.regex.PatternSyntaxException ; 38 39 46 public class JavadocTypeCheck 47 extends Check 48 { 49 50 private Scope mScope = Scope.PRIVATE; 51 52 private Scope mExcludeScope; 53 54 private Pattern mAuthorFormatPattern; 55 56 private Pattern mVersionFormatPattern; 57 58 private String mAuthorFormat; 59 60 private String mVersionFormat; 61 65 private boolean mAllowMissingParamTags; 66 67 71 public void setScope(String aFrom) 72 { 73 mScope = Scope.getInstance(aFrom); 74 } 75 76 80 public void setExcludeScope(String aScope) 81 { 82 mExcludeScope = Scope.getInstance(aScope); 83 } 84 85 90 public void setAuthorFormat(String aFormat) 91 throws ConversionException 92 { 93 try { 94 mAuthorFormat = aFormat; 95 mAuthorFormatPattern = Utils.getPattern(aFormat); 96 } 97 catch (final PatternSyntaxException e) { 98 throw new ConversionException("unable to parse " + aFormat, e); 99 } 100 } 101 102 107 public void setVersionFormat(String aFormat) 108 throws ConversionException 109 { 110 try { 111 mVersionFormat = aFormat; 112 mVersionFormatPattern = Utils.getPattern(aFormat); 113 } 114 catch (final PatternSyntaxException e) { 115 throw new ConversionException("unable to parse " + aFormat, e); 116 } 117 118 } 119 120 126 public void setAllowMissingParamTags(boolean aFlag) 127 { 128 mAllowMissingParamTags = aFlag; 129 } 130 131 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 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 final Vector tags = getJavadocTags(cmt); 155 checkTag(lineNo, tags, "author", 156 mAuthorFormatPattern, mAuthorFormat); 157 checkTag(lineNo, tags, "version", 158 mVersionFormatPattern, mVersionFormat); 159 160 final List typeParamNames = 161 CheckUtils.getTypeParameterNames(aAST); 162 163 if (!mAllowMissingParamTags) { 164 for (final Iterator typeParamNameIt = 166 typeParamNames.iterator(); 167 typeParamNameIt.hasNext();) 168 { 169 checkTypeParamTag( 170 lineNo, tags, (String ) typeParamNameIt.next()); 171 } 172 } 173 174 checkUnusedTypeParamTags(tags, typeParamNames); 175 } 176 } 177 } 178 179 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 206 private Vector getJavadocTags(TextBlock aCmt) 207 { 208 final String [] text = aCmt.getText(); 209 final Vector tags = new Vector (); 210 Pattern tagPattern = Utils.getPattern("/\\*{2,}\\s*@(\\p{Alpha}+)\\s"); 211 for (int i = 0; i < text.length; i++) { 212 final String s = text[i]; 213 final Matcher tagMatcher = tagPattern.matcher(s); 214 if (tagMatcher.find()) { 215 final String tagName = tagMatcher.group(1); 216 String 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 240 private void checkTag(int aLineNo, Vector aTags, String aTag, 241 Pattern aFormatPattern, String 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 269 private void checkTypeParamTag( 270 final int aLineNo, final Vector aTags, final String 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 292 private void checkUnusedTypeParamTags( 293 final Vector aTags, 294 final List aTypeParamNames) 295 { 296 final Pattern 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 matcher = pattern.matcher(tag.getArg1()); 304 String 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 |