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

spoon.javadoc.internal.Javadoc Maven / Gradle / Ivy

Go to download

Spoon is a tool for meta-programming, analysis and transformation of Java programs.

There is a newer version: 11.1.1-beta-14
Show newest version
/*
 * SPDX-License-Identifier: (MIT OR CECILL-C)
 *
 * Copyright (C) 2006-2023 INRIA and contributors
 *
 * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) or the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
 */
/**
 *  This file originally comes from JavaParser and is distributed under the terms of
 * a) the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * b) the terms of the Apache License
 */
package spoon.javadoc.internal;

import static spoon.javadoc.internal.JavadocInlineTag.nextWord;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import spoon.reflect.code.CtComment;

/**
 * The structured content of a single Javadoc comment.
 *
 * 

It is composed by a description and a list of block tags. * *

An example would be the text contained in this very Javadoc comment. At the moment of this * writing this comment does not contain any block tags (such as @see AnotherClass) * * @deprecated Use the new javadoc parser submodule, see Javadoc Parser. */ @Deprecated(forRemoval = true, since = "11.0.0") public class Javadoc implements Serializable { private static final long serialVersionUID = 1L; private JavadocDescription description; private List blockTags; public Javadoc() { this(new JavadocDescription()); } public Javadoc(JavadocDescription description) { this.description = description; this.blockTags = new LinkedList<>(); } public Javadoc addBlockTag(JavadocBlockTag blockTag) { this.blockTags.add(blockTag); return this; } /** For tags like "@return good things" where tagName is "return", and the rest is content. */ public Javadoc addBlockTag(String tagName, String parameter, String content) { return addBlockTag(tagName, parameter, content); } public Javadoc addBlockTag(String tagName) { return addBlockTag(tagName, "", ""); } /** * Return the text content of the document. It does not containing trailing spaces and asterisks * at the start of the line. */ public String toText() { StringBuilder sb = new StringBuilder(); if (!description.isEmpty()) { sb.append(description.toText()); sb.append(System.lineSeparator()); } if (!blockTags.isEmpty()) { sb.append(System.lineSeparator()); } blockTags.forEach( bt -> { sb.append(bt.toText()); sb.append(System.lineSeparator()); }); return sb.toString(); } public JavadocDescription getDescription() { return description; } /** @return the current List of associated JavadocBlockTags */ public List getBlockTags() { return this.blockTags; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Javadoc document = (Javadoc) o; return description.equals(document.description) && blockTags.equals(document.blockTags); } @Override public int hashCode() { int result = description.hashCode(); result = 31 * result + blockTags.hashCode(); return result; } @Override public String toString() { return "Javadoc{" + "description=" + description + ", blockTags=" + blockTags + '}'; } private static String BLOCK_TAG_PREFIX = "@"; private static Pattern BLOCK_PATTERN = Pattern.compile("^\\s*" + BLOCK_TAG_PREFIX, Pattern.MULTILINE); /** parse the description part (before tags) of a Javadoc */ public static JavadocDescription parseText(String text) { JavadocDescription instance = new JavadocDescription(); int index = 0; Pair nextInlineTagPos; while ((nextInlineTagPos = indexOfNextInlineTag(text, index)) != null) { if (nextInlineTagPos.getLeft() != index) { instance.addElement(new JavadocSnippet(text.substring(index, nextInlineTagPos.getLeft()))); } instance.addElement( JavadocInlineTag.fromText(text.substring(nextInlineTagPos.getLeft(), nextInlineTagPos.getRight() + 1))); index = nextInlineTagPos.getRight() + 1; } if (index < text.length()) { instance.addElement(new JavadocSnippet(text.substring(index))); } return instance; } private static Pair indexOfNextInlineTag(String text, int start) { int index = text.indexOf("{@", start); if (index == -1) { return null; } // Find the corresponding end curly brace: // // Tag doesn't end here // | // v // {@code public class Foo {}} // ^ ^ // | | // index Tag ends here int closeIndex = -1; int nesting = 1; for (int i = index + 2; i < text.length(); i++) { char read = text.charAt(i); if (read == '{') { nesting++; } else if (read == '}') { nesting--; } if (nesting == 0) { closeIndex = i; break; } } if (closeIndex == -1) { return null; } return Pair.of(index, closeIndex); } /** parses the Javadoc content (description + tags) */ public static Javadoc parse(String commentContent) { List cleanLines; cleanLines = Arrays.asList(commentContent.split(CtComment.LINE_SEPARATOR)); int indexOfFirstBlockTag = cleanLines .stream() .filter(Javadoc::isABlockLine) .map(cleanLines::indexOf) .findFirst() .orElse(-1); List blockLines; String descriptionText; if (indexOfFirstBlockTag == -1) { descriptionText = String.join(CtComment.LINE_SEPARATOR, cleanLines).stripTrailing(); blockLines = Collections.emptyList(); } else { descriptionText = String.join(CtComment.LINE_SEPARATOR, cleanLines.subList(0, indexOfFirstBlockTag)) .stripTrailing(); // Combine cleaned lines, but only starting with the first block tag till the end // In this combined string it is easier to handle multiple lines which actually belong // together String tagBlock = cleanLines .subList(indexOfFirstBlockTag, cleanLines.size()) .stream() .collect(Collectors.joining(CtComment.LINE_SEPARATOR)); // Split up the entire tag back again, considering now that some lines belong to the // same // block tag. // The pattern splits the block at each new line starting with the '@' symbol, thus the // symbol // then needs to be added again so that the block parsers handles everything correctly. blockLines = BLOCK_PATTERN .splitAsStream(tagBlock) .filter(x -> !x.isEmpty()) .map(s -> BLOCK_TAG_PREFIX + s) .collect(Collectors.toList()); } Javadoc document = new Javadoc(parseText(descriptionText)); blockLines.forEach(l -> document.addBlockTag(parseBlockTag(l))); return document; } private static JavadocBlockTag parseBlockTag(String line) { line = line.trim().substring(1); String tagName = nextWord(line); String rest = line.substring(tagName.length()).trim(); return new JavadocBlockTag(tagName, rest); } private static boolean isABlockLine(String line) { return line.trim().startsWith(BLOCK_TAG_PREFIX); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy