/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.ast; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.sourceforge.pmd.util.StringUtil; public final class CommentUtil { private static final String CR = "\n"; private static final Pattern JAVADOC_TAG = Pattern.compile("@[A-Za-z0-9]+"); private static final Map<String, String> JAVADOC_CACHE = new HashMap<>(); private CommentUtil() { } public static String wordAfter(String text, int position) { if (position >= text.length()) { return null; } int newposition = position + 1; int end = newposition; char ch = text.charAt(end); while (Character.isLetterOrDigit(ch) && end < text.length()) { ch = text.charAt(++end); } return text.substring(newposition, end); } public static String javadocContentAfter(String text, int position) { int endPos = text.indexOf('\n', position); if (endPos < 0) { return null; } if (StringUtil.isNotEmpty(text.substring(position, endPos))) { return text.substring(position, endPos).trim(); } if (text.indexOf('@', endPos) >= 0) { return null; // nope, this is another entry } // try next line int nextEndPos = text.indexOf('\n', endPos + 1); if (StringUtil.isNotEmpty(text.substring(endPos, nextEndPos))) { return text.substring(endPos, nextEndPos).trim(); } return null; } public static Map<String, Integer> javadocTagsIn(String comment) { Matcher m = JAVADOC_TAG.matcher(comment); Map<String, Integer> tags = null; while (m.find()) { if (tags == null) { tags = new HashMap<>(); } String match = comment.substring(m.start() + 1, m.end()); String tag = JAVADOC_CACHE.get(match); if (tag == null) { JAVADOC_CACHE.put(match, match); } tags.put(tag, m.start()); } if (tags == null) { return Collections.emptyMap(); } return tags; } public static List<String> multiLinesIn(String comment) { String[] lines = comment.split(CR); List<String> filteredLines = new ArrayList<>(lines.length); for (String rawLine : lines) { String line = rawLine.trim(); if (line.startsWith("//")) { filteredLines.add(line.substring(2)); continue; } if (line.endsWith("*/")) { int end = line.length() - 2; int start = line.startsWith("/**") ? 3 : line.startsWith("/*") ? 2 : 0; filteredLines.add(line.substring(start, end)); continue; } if (line.charAt(0) == '*') { filteredLines.add(line.substring(1)); continue; } if (line.startsWith("/**")) { filteredLines.add(line.substring(3)); continue; } if (line.startsWith("/*")) { filteredLines.add(line.substring(2)); continue; } filteredLines.add(line); } return filteredLines; } /** * Similar to the String.trim() function, this one removes the leading and * trailing empty/blank lines from the line list. * * @param lines */ public static List<String> trim(List<String> lines) { int firstNonEmpty = 0; for (; firstNonEmpty < lines.size(); firstNonEmpty++) { if (StringUtil.isNotEmpty(lines.get(firstNonEmpty))) { break; } } // all of them empty? if (firstNonEmpty == lines.size()) { return Collections.emptyList(); } int lastNonEmpty = lines.size() - 1; for (; lastNonEmpty > 0; lastNonEmpty--) { if (StringUtil.isNotEmpty(lines.get(lastNonEmpty))) { break; } } List<String> filtered = new ArrayList<>(); for (int i = firstNonEmpty; i < lastNonEmpty; i++) { filtered.add(lines.get(i)); } return filtered; } public static void main(String[] args) { Collection<String> tags = javadocTagsIn(args[0]).keySet(); for (String tag : tags) { System.out.println(tag); } } }