001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 the original author or authors. 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//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.javadoc.utils; 021 022import java.util.ArrayList; 023import java.util.List; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027import com.puppycrawl.tools.checkstyle.api.LineColumn; 028 029/** 030 * Tools for parsing block tags from a Javadoc comment. 031 * 032 */ 033public final class BlockTagUtil { 034 035 /** Block tag pattern for a first line. */ 036 private static final Pattern BLOCK_TAG_PATTERN_FIRST_LINE = Pattern.compile( 037 "/\\*{2,}\\s*@(\\p{Alpha}+)\\s"); 038 039 /** Block tag pattern. */ 040 private static final Pattern BLOCK_TAG_PATTERN = Pattern.compile( 041 "^\\s*\\**\\s*@(\\p{Alpha}+)\\s"); 042 043 /** Closing tag. */ 044 private static final String JAVADOC_CLOSING_TAG = "*/"; 045 046 /** Prevent instantiation. */ 047 private BlockTagUtil() { 048 } 049 050 /** 051 * Extract the block tags from a Javadoc comment. 052 * @param lines The text of the comment, as separate lines. 053 * @return The tags extracted from the block. 054 */ 055 public static List<TagInfo> extractBlockTags(String... lines) { 056 final List<TagInfo> tags = new ArrayList<>(); 057 058 for (int i = 0; i < lines.length; i++) { 059 // Starting lines of a comment have a different first line pattern. 060 final boolean isFirstLine = i == 0; 061 final Pattern pattern; 062 if (isFirstLine) { 063 pattern = BLOCK_TAG_PATTERN_FIRST_LINE; 064 } 065 else { 066 pattern = BLOCK_TAG_PATTERN; 067 } 068 069 final String line = lines[i]; 070 final Matcher tagMatcher = pattern.matcher(line); 071 072 if (tagMatcher.find()) { 073 final String tagName = tagMatcher.group(1); 074 075 // offset of one for the @ character 076 final int colNum = tagMatcher.start(1) - 1; 077 final int lineNum = i + 1; 078 079 final String remainder = line.substring(tagMatcher.end(1)); 080 String tagValue = remainder.trim(); 081 082 // Handle the case where we're on the last line of a Javadoc comment. 083 if (tagValue.endsWith(JAVADOC_CLOSING_TAG)) { 084 final int endIndex = tagValue.length() - JAVADOC_CLOSING_TAG.length(); 085 tagValue = tagValue.substring(0, endIndex).trim(); 086 } 087 088 final LineColumn position = new LineColumn(lineNum, colNum); 089 tags.add(new TagInfo(tagName, tagValue, position)); 090 } 091 } 092 093 return tags; 094 } 095 096}