001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2018 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 BlockTagUtils {
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 BlockTagUtils() {
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}