001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.javadoc; 020 021import com.google.common.collect.Lists; 022import com.puppycrawl.tools.checkstyle.api.JavadocTagInfo; 023import com.puppycrawl.tools.checkstyle.api.TextBlock; 024import com.puppycrawl.tools.checkstyle.api.Utils; 025import java.util.List; 026import java.util.regex.Matcher; 027import java.util.regex.Pattern; 028 029/** 030 * Contains utility methods for working with Javadoc. 031 * @author Lyle Hanson 032 */ 033public final class JavadocUtils 034{ 035 ///CLOVER:OFF 036 /** prevent instantiation */ 037 private JavadocUtils() 038 { 039 } 040 ///CLOVER:ON 041 042 /** 043 * Gets validTags from a given piece of Javadoc. 044 * @param aCmt the Javadoc comment to process. 045 * @param aTagType the type of validTags we're interested in 046 * @return all standalone validTags from the given javadoc. 047 */ 048 public static JavadocTags getJavadocTags(TextBlock aCmt, 049 JavadocTagType aTagType) 050 { 051 final String[] text = aCmt.getText(); 052 final List<JavadocTag> tags = Lists.newArrayList(); 053 final List<InvalidJavadocTag> invalidTags = Lists.newArrayList(); 054 Pattern blockTagPattern = 055 Utils.getPattern("/\\*{2,}\\s*@(\\p{Alpha}+)\\s"); 056 for (int i = 0; i < text.length; i++) { 057 final String s = text[i]; 058 final Matcher blockTagMatcher = blockTagPattern.matcher(s); 059 if ((aTagType.equals(JavadocTagType.ALL) || aTagType 060 .equals(JavadocTagType.BLOCK)) && blockTagMatcher.find()) 061 { 062 final String tagName = blockTagMatcher.group(1); 063 String content = s.substring(blockTagMatcher.end(1)); 064 if (content.endsWith("*/")) { 065 content = content.substring(0, content.length() - 2); 066 } 067 final int line = aCmt.getStartLineNo() + i; 068 int col = blockTagMatcher.start(1) - 1; 069 if (i == 0) { 070 col += aCmt.getStartColNo(); 071 } 072 if (JavadocTagInfo.isValidName(tagName)) { 073 tags.add( 074 new JavadocTag(line, col, tagName, content.trim())); 075 } 076 else { 077 invalidTags.add(new InvalidJavadocTag(line, col, tagName)); 078 } 079 } 080 // No block tag, so look for inline validTags 081 else if (aTagType.equals(JavadocTagType.ALL) 082 || aTagType.equals(JavadocTagType.INLINE)) 083 { 084 // Match JavaDoc text after comment characters 085 final Pattern commentPattern = 086 Utils.getPattern("^\\s*(?:/\\*{2,}|\\*+)\\s*(.*)"); 087 final Matcher commentMatcher = commentPattern.matcher(s); 088 final String commentContents; 089 final int commentOffset; // offset including comment characters 090 if (!commentMatcher.find()) { 091 commentContents = s; // No leading asterisks, still valid 092 commentOffset = 0; 093 } 094 else { 095 commentContents = commentMatcher.group(1); 096 commentOffset = commentMatcher.start(1) - 1; 097 } 098 final Pattern tagPattern = 099 Utils.getPattern(".*?\\{@(\\p{Alpha}+)\\s+(.*?)\\}"); 100 final Matcher tagMatcher = tagPattern.matcher(commentContents); 101 while (tagMatcher.find()) { 102 if (tagMatcher.groupCount() == 2) { 103 final String tagName = tagMatcher.group(1); 104 final String tagValue = tagMatcher.group(2).trim(); 105 final int line = aCmt.getStartLineNo() + i; 106 int col = commentOffset + (tagMatcher.start(1) - 1); 107 if (i == 0) { 108 col += aCmt.getStartColNo(); 109 } 110 if (JavadocTagInfo.isValidName(tagName)) { 111 tags.add(new JavadocTag(line, col, tagName, 112 tagValue)); 113 } 114 else { 115 invalidTags.add(new InvalidJavadocTag(line, col, 116 tagName)); 117 } 118 } 119 // else Error: Unexpected match count for inline JavaDoc 120 // tag! 121 } 122 } 123 blockTagPattern = 124 Utils.getPattern("^\\s*\\**\\s*@(\\p{Alpha}+)\\s"); 125 } 126 return new JavadocTags(tags, invalidTags); 127 } 128 129 /** 130 * The type of Javadoc tag we want returned. 131 */ 132 public enum JavadocTagType 133 { 134 /** block type. */ 135 BLOCK, 136 /** inline type. */ 137 INLINE, 138 /** all validTags. */ 139 ALL; 140 } 141}