001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2024 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     *
053     * @param lines The text of the comment, as separate lines.
054     * @return The tags extracted from the block.
055     */
056    public static List<TagInfo> extractBlockTags(String... lines) {
057        final List<TagInfo> tags = new ArrayList<>();
058
059        for (int i = 0; i < lines.length; i++) {
060            // Starting lines of a comment have a different first line pattern.
061            final boolean isFirstLine = i == 0;
062            final Pattern pattern;
063            if (isFirstLine) {
064                pattern = BLOCK_TAG_PATTERN_FIRST_LINE;
065            }
066            else {
067                pattern = BLOCK_TAG_PATTERN;
068            }
069
070            final String line = lines[i];
071            final Matcher tagMatcher = pattern.matcher(line);
072
073            if (tagMatcher.find()) {
074                final String tagName = tagMatcher.group(1);
075
076                // offset of one for the @ character
077                final int colNum = tagMatcher.start(1) - 1;
078                final int lineNum = i + 1;
079
080                final String remainder = line.substring(tagMatcher.end(1));
081                String tagValue = remainder.trim();
082
083                // Handle the case where we're on the last line of a Javadoc comment.
084                if (tagValue.endsWith(JAVADOC_CLOSING_TAG)) {
085                    final int endIndex = tagValue.length() - JAVADOC_CLOSING_TAG.length();
086                    tagValue = tagValue.substring(0, endIndex).trim();
087                }
088
089                final LineColumn position = new LineColumn(lineNum, colNum);
090                tags.add(new TagInfo(tagName, tagValue, position));
091            }
092        }
093
094        return tags;
095    }
096
097}