All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.pmd.lang.java.ast.JavaComment Maven / Gradle / Ivy

The newest version!
/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

package net.sourceforge.pmd.lang.java.ast;

import java.util.stream.Stream;

import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeNode;
import net.sourceforge.pmd.lang.document.Chars;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
import net.sourceforge.pmd.reporting.Reportable;
import net.sourceforge.pmd.util.IteratorUtil;

/**
 * Wraps a comment token to provide some utilities.
 * This is not a node, it's not part of the tree anywhere,
 * just convenient.
 *
 * 

This class represents any kind of comment. A specialized subclass * provides more API for Javadoc comments, see {@link JavadocComment}. */ public class JavaComment implements Reportable { //TODO maybe move part of this into pmd core private final JavaccToken token; JavaComment(JavaccToken t) { this.token = t; } @Override public FileLocation getReportLocation() { return getToken().getReportLocation(); } /** The token underlying this comment. */ public final JavaccToken getToken() { return token; } public boolean isSingleLine() { return token.kind == JavaTokenKinds.SINGLE_LINE_COMMENT; } public boolean hasJavadocContent() { return token.kind == JavaTokenKinds.FORMAL_COMMENT || JavaAstUtils.isMarkdownComment(token); } /** Returns the full text of the comment. */ public Chars getText() { return getToken().getImageCs(); } /** * Returns true if the given token has the kind * of a comment token (there are three such kinds). */ public static boolean isComment(JavaccToken token) { return JavaAstUtils.isComment(token); } /** * Removes the leading comment marker (like {@code *}) of each line * of the comment as well as the start marker ({@code //}, {@code /*}, {@code /**} or {@code ///} * and the end markers (*/). * *

Empty lines are removed. * * @return List of lines of the comments */ public Iterable getFilteredLines() { return getFilteredLines(false); } public Iterable getFilteredLines(boolean preserveEmptyLines) { if (preserveEmptyLines) { return () -> IteratorUtil.map(getText().lines().iterator(), JavaComment::removeCommentMarkup); } else { return () -> IteratorUtil.mapNotNull( getText().lines().iterator(), line -> { line = removeCommentMarkup(line); return line.isEmpty() ? null : line; } ); } } /** * True if this is a comment delimiter or an asterisk. This * tests the whole parameter and not a prefix/suffix. */ @SuppressWarnings("PMD.LiteralsFirstInComparisons") // a fp public static boolean isMarkupWord(Chars word) { return word.length() <= 3 && (word.contentEquals("*") || word.contentEquals("//") || word.contentEquals("///") || word.contentEquals("/*") || word.contentEquals("*/") || word.contentEquals("/**")); } /** * Trim the start of the provided line to remove a comment * markup opener ({@code //, ///, /*, /**, *}) or closer */. */ public static Chars removeCommentMarkup(Chars line) { line = line.trim().removeSuffix("*/"); int subseqFrom = 0; if (line.startsWith('/', 0)) { if (line.startsWith("**", 1) || line.startsWith("//", 1)) { subseqFrom = 3; } else if (line.startsWith('/', 1) || line.startsWith('*', 1)) { subseqFrom = 2; } } else if (line.startsWith('*', 0)) { subseqFrom = 1; } return line.subSequence(subseqFrom, line.length()).trim(); } private static Stream getSpecialTokensIn(JjtreeNode node) { return GenericToken.streamRange(node.getFirstToken(), node.getLastToken()) .flatMap(it -> IteratorUtil.toStream(GenericToken.previousSpecials(it).iterator())); } public static Stream getLeadingComments(JavaNode node) { Stream specialTokens; if (node instanceof ModifierOwner) { node = ((ModifierOwner) node).getModifiers(); specialTokens = getSpecialTokensIn(node); // if this was a non-implicit empty modifier node, we should also consider comments immediately after if (!node.getFirstToken().isImplicit()) { specialTokens = Stream.concat(specialTokens, getSpecialTokensIn(node.getNextSibling())); } } else { specialTokens = getSpecialTokensIn(node); } return specialTokens.filter(JavaComment::isComment) .map(JavaComment::toComment); } private static JavaComment toComment(JavaccToken tok) { switch (tok.kind) { case JavaTokenKinds.FORMAL_COMMENT: return new JavadocComment(tok); case JavaTokenKinds.MULTI_LINE_COMMENT: case JavaTokenKinds.SINGLE_LINE_COMMENT: return new JavaComment(tok); default: throw new IllegalArgumentException("Token is not a comment: " + tok); } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof JavaComment)) { return false; } JavaComment that = (JavaComment) o; return token.equals(that.token); } @Override public int hashCode() { return token.hashCode(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy