fix(JavaDoc-gen): compilation on backport, Better rendering, respect IDE options

Fixes IDEA-354610, IDEA-353932
Partially addresses IDEA-352642

fix(JavaDoc-format): handle indent on markdown

fix(JavaDoc-backport): fix compilation

GitOrigin-RevId: 5d1705da21be59ec0bc92a1b35bdf986a3227064
This commit is contained in:
Mathias Boulay
2024-09-06 10:57:58 +02:00
committed by intellij-monorepo-bot
parent 0dc015188d
commit 2cfd03bd80
16 changed files with 460 additions and 79 deletions

View File

@@ -62,7 +62,6 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.XmlStringUtil;
import kotlin.text.StringsKt;
import org.jdom.Element;
import org.jdom.JDOMException;
@@ -1859,7 +1858,7 @@ public class JavaDocInfoGenerator {
}
else if (element instanceof PsiMarkdownCodeBlock markdownCodeBlock) {
if (markdownCodeBlock.isInline()) {
appendWrappedWithInlineCodeTag(subBuffer, markdownCodeBlock.getCodeText());
appendStyledInlineCode(subBuffer, element.getProject(), markdownCodeBlock.getLanguage(), markdownCodeBlock.getCodeText());
} else {
appendStyledCodeBlock(subBuffer, element.getProject(), markdownCodeBlock.getCodeLanguage(), markdownCodeBlock.getCodeText());
}
@@ -1927,7 +1926,9 @@ public class JavaDocInfoGenerator {
appendHighlightedByLexerAndEncodedAsHtmlCodeSnippet(
doHighlightCodeBlocks(), buffer, myProject, JavaLanguage.INSTANCE,
StringUtil.unescapeXmlEntities(StringUtil.replaceUnicodeEscapeSequences(htmlCodeBlockContents.toString()))
.replace(" ", " "));
.replace(" ", " ")
.replace("@", "@")
);
buffer.append(CODE_BLOCK_SUFFIX);
appendPlainText(buffer, text.substring(suffixIndex + delimiters.second.length()));
return null;
@@ -2241,26 +2242,15 @@ public class JavaDocInfoGenerator {
private static boolean isCodeBlock(PsiInlineDocTag tag) {
if (!CODE_TAG.equals(tag.getName())) return false;
ASTNode prevNode = tag.getNode().getTreePrev();
while (prevNode != null) {
String text = prevNode.getText();
if (prevNode.getElementType() == JavaDocTokenType.DOC_COMMENT_DATA) {
if (StringUtil.endsWithIgnoreCase(StringUtil.trim(text), "<pre>")) {
return true;
}
if (StringUtil.startsWithIgnoreCase(StringUtil.trim(text), "</pre>")) {
return false;
}
}
prevNode = prevNode.getTreePrev();
}
return false;
return isInPre(tag);
}
private void generateCodeValue(PsiInlineDocTag tag, StringBuilder buffer) {
boolean isCodeBlock = isCodeBlock(tag);
StringBuilder codeSnippetBuilder = new StringBuilder();
generateLiteralValue(codeSnippetBuilder, tag, false);
if (isCodeBlock) {
// remove excess whitespaces between tags e.g. in `<pre> {@code`
int lastNonWhite = buffer.length() - 1;
@@ -2268,37 +2258,11 @@ public class JavaDocInfoGenerator {
buffer.setLength(lastNonWhite + 1);
// Remove preceding <pre> fragment
StringUtil.trimEnd(buffer, "<pre>");
appendStyledCodeBlock(buffer, tag.getProject(), tag.getLanguage(), codeSnippetBuilder.toString());
} else {
String codeSnippet = codeSnippetBuilder.toString().replace("\n", "").trim();
appendStyledInlineCode(buffer, tag.getProject(), tag.getLanguage(), codeSnippet);
}
buffer.append(isCodeBlock ? CODE_BLOCK_PREFIX : INLINE_CODE_PREFIX);
int pos = buffer.length();
StringBuilder codeSnippetBuilder = new StringBuilder();
generateLiteralValue(codeSnippetBuilder, tag, false);
String codeSnippet = codeSnippetBuilder.toString();
if (isCodeBlock) {
codeSnippet = StringsKt.trimIndent(codeSnippet);
}
if (isCodeBlock && doHighlightCodeBlocks()
|| !isCodeBlock && getInlineCodeHighlightingMode() == InlineCodeHighlightingMode.SEMANTIC_HIGHLIGHTING) {
// highlights code by lexer
codeSnippetBuilder.setLength(0);
appendHighlightedByLexerAndEncodedAsHtmlCodeSnippet(true, codeSnippetBuilder, tag.getProject(), tag.getLanguage(), codeSnippet);
codeSnippet = codeSnippetBuilder.toString();
}
else {
codeSnippet = XmlStringUtil.escapeString(codeSnippet);
}
if (!isCodeBlock) {
// we are in inline @code block, we should remove all new lines
codeSnippet = codeSnippet.replace(BR_TAG, "");
}
buffer.append(codeSnippet);
buffer.append(isCodeBlock ? CODE_BLOCK_SUFFIX : INLINE_CODE_SUFFIX);
if (buffer.charAt(pos) == '\n') buffer.insert(pos, ' '); // line break immediately after opening tag is ignored by JEditorPane
}
private void generateLiteralValue(StringBuilder buffer, PsiDocTag tag, boolean doEscaping) {
@@ -2322,8 +2286,8 @@ public class JavaDocInfoGenerator {
}
}
private static boolean isInPre(PsiDocTag tag) {
PsiElement sibling = tag.getPrevSibling();
private static boolean isInPre(PsiElement element) {
PsiElement sibling = element.getPrevSibling();
while (sibling != null) {
if (sibling instanceof PsiDocToken) {
String text = StringUtil.toLowerCase(sibling.getText());

View File

@@ -46,6 +46,25 @@ public class JDParser {
private static final Pattern PRE_TAG_START_PATTERN = Pattern.compile(PRE_TAG_START_REGEXP);
private static final Pattern SNIPPET_START_PATTERN = Pattern.compile(SNIPPET_START_REGEXP);
// Markdown tokens
private static final String CODE_FENCE_BACKTICK = "```";
private static final String CODE_FENCE_TILDE = "~~~";
private static final String CODE_FENCE_BACKTICK_REGEXP = "`{3,}";
private static final String CODE_FENCE_TILDE_REGEXP = "~{3,}";
private static final Pattern CODE_FENCE_TILDE_PATTERN = Pattern.compile(CODE_FENCE_TILDE_REGEXP);
private static final Pattern CODE_FENCE_BACKTICK_PATTERN = Pattern.compile(CODE_FENCE_BACKTICK_REGEXP);
private static final String LIST_ITEM_REGEXP = "^\\d+?[).]";
private static final Pattern LIST_ITEM_PATTERN = Pattern.compile(LIST_ITEM_REGEXP);
private static final String LIST_ITEM_START = "- ";
private static final String LIST_ITEM_START_2 = "+ ";
private static final String LIST_ITEM_START_3 = "* ";
private static final String LINE_SEPARATOR = "---";
private static final String HEADER_START = "#";
private static final String BLOCKQUOTE_START = ">";
private static final String TABLE_ROW_START = "|";
private static final String[] TAGS_TO_KEEP_INDENTS_AFTER = {"table", "ol", "ul", "div", "dl"};
public JDParser(@NotNull CodeStyleSettings settings) {
@@ -184,7 +203,7 @@ public class JDParser {
// Note: Markdown comments are not trimmed like html ones, except for javadoc tags
String newLine;
int tagStart = CharArrayUtil.shiftForward(line, 3, " \t");
if (tagStart != line.length()) {
if (tagStart != line.length() && line.charAt(tagStart) == '@') {
newLine = line.substring(tagStart);
} else {
newLine = StringUtil.trimStart(line, "/// ");
@@ -259,17 +278,17 @@ public class JDParser {
/**
* Breaks the specified string by the specified separators into array of strings
*
* @param s the specified string
* @param markers if this parameter is not null then it will be filled with Boolean values:
* true if the corresponding line in returned list is inside &lt;pre&gt; tag,
* false if it is outside
* @param s the specified string
* @param markers if this parameter is not null then it will be filled with Boolean values:
* true if the corresponding line in returned list is inside &lt;pre&gt; tag or a markdown codeblock,
* false if it is outside
* @return list of strings (lines)
*/
private @Nullable List<String> toArray(@Nullable String s, @Nullable List<Boolean> markers, boolean markdownComment) {
if (s == null) return null;
s = s.trim();
s = markdownComment ? s : s.trim();
if (s.isEmpty()) return null;
boolean p2nl = markers != null && mySettings.JD_P_AT_EMPTY_LINES;
boolean p2nl = markers != null && mySettings.JD_P_AT_EMPTY_LINES && !markdownComment;
List<String> list = new ArrayList<>();
StringTokenizer st = new StringTokenizer(s, "\n", true);
boolean first = true;
@@ -280,6 +299,7 @@ public class JDParser {
boolean isInMultilineTodo = false;
boolean isInSnippet = false;
int snippetBraceBalance = 0;
String codeblockType = null;
while (st.hasMoreTokens()) {
String token = st.nextToken();
@@ -330,8 +350,25 @@ public class JDParser {
snippetBraceBalance += getLineSnippetTagBraceBalance(token);
}
if (lineHasUnclosedPreTag(token)) preCount++;
markers.add(preCount > 0 || firstLineToKeepIndents >= 0 || isInMultilineTodo || snippetBraceBalance != 0);
if (markdownComment && codeblockType == null) {
codeblockType = lineGetStartCodeFence(token);
if (codeblockType != null) preCount++;
}
markers.add(preCount > 0
|| firstLineToKeepIndents >= 0
|| isInMultilineTodo
|| snippetBraceBalance != 0
|| (markdownComment && isStartOfMarkdownHeader(token)) /* Markdown titles cannot be split */);
if (lineHasClosingPreTag(token)) preCount--;
if (markdownComment && codeblockType != null) {
if (Strings.areSameInstance(codeblockType, CODE_FENCE_BACKTICK) && token.contains(CODE_FENCE_BACKTICK)
|| Strings.areSameInstance(codeblockType, CODE_FENCE_TILDE) && token.contains(CODE_FENCE_TILDE)) {
preCount--;
codeblockType = null;
}
}
}
}
@@ -446,7 +483,7 @@ public class JDParser {
while (true) {
if (seq.length() < width || isMarked) {
// keep remaining line and proceed with next paragraph
seq = isMarked ? seq : seq.trim();
seq = isMarked || markdownComment ? seq : seq.trim();
list.add(seq);
break;
}
@@ -542,7 +579,7 @@ public class JDParser {
@Contract("null, _ -> null")
private List<Pair<String, Boolean>> splitToParagraphs(@Nullable String s, boolean markdownComment) {
if (s == null) return null;
s = s.trim();
s = markdownComment ? s : s.trim();
if (s.isEmpty()) return null;
List<Pair<String, Boolean>> result = new ArrayList<>();
@@ -556,10 +593,7 @@ public class JDParser {
for (int i = 0; i < list.size(); i++) {
String s1 = list.get(i);
if (marks[i].booleanValue()) {
if (sb.length() != 0) {
result.add(new Pair<>(sb.toString(), false));
sb.setLength(0);
}
endParagraph(result, sb);
result.add(Pair.create(s1, marks[i]));
}
else {
@@ -568,8 +602,18 @@ public class JDParser {
result.add(Pair.create(s1, marks[i]));
}
else {
if (isStartOfMarkdownConstruct(s1)) {
endParagraph(result, sb);
}
if (sb.length() != 0) sb.append(' ');
sb.append(s1);
if (markdownComment && !sb.isEmpty()) {
// When fusing lines together, horizontal spacing loses its meaning
sb.append(s1.trim());
}
else {
sb.append(s1);
}
}
}
}
@@ -583,6 +627,34 @@ public class JDParser {
return mySettings.JD_PRESERVE_LINE_FEEDS || HtmlUtil.startsWithTag(line);
}
/**
* @return Whether there is a star of a markdown construct
* That should not be merged into a single paragraph
*/
private static boolean isStartOfMarkdownConstruct(@NotNull String line) {
String trimmedLine = line.trim();
return trimmedLine.startsWith(BLOCKQUOTE_START)
|| trimmedLine.startsWith(LINE_SEPARATOR)
|| isStartOfMarkdownHeader(trimmedLine)
|| isMarkdownTableRow(trimmedLine)
|| isStartOfMarkdownListItem(trimmedLine);
}
private static boolean isStartOfMarkdownHeader(@NotNull String line) {
return line.trim().startsWith(HEADER_START);
}
private static boolean isStartOfMarkdownListItem(@NotNull String line) {
return line.startsWith(LIST_ITEM_START)
|| line.startsWith(LIST_ITEM_START_2)
|| line.startsWith(LIST_ITEM_START_3)
|| LIST_ITEM_PATTERN.matcher(line).find();
}
private static boolean isMarkdownTableRow(@NotNull String line) {
return line.startsWith(TABLE_ROW_START) && StringUtil.getOccurrenceCount(line, TABLE_ROW_START) > 1;
}
private static void endParagraph(@NotNull List<? super Pair<String, Boolean>> result, @NotNull StringBuilder sb) {
if (sb.length() > 0) {
result.add(new Pair<>(sb.toString(), false));
@@ -720,6 +792,41 @@ public class JDParser {
return StringUtil.getOccurrenceCount(line, PRE_TAG_END) > getOccurenceCount(line, PRE_TAG_START_PATTERN);
}
/**
* Detects a stating code block fence in a given line
*
* @return The code fence type, or null if none are found
*/
private static String lineGetStartCodeFence(@NotNull String line) {
int backticks = getOccurenceCount(line, CODE_FENCE_BACKTICK_PATTERN);
int tildes = getOccurenceCount(line, CODE_FENCE_TILDE_PATTERN);
boolean hasBacktickStart = backticks % 2 != 0;
boolean hasTildeStart = tildes % 2 != 0;
if (hasBacktickStart && hasTildeStart) {
if (backticks == tildes) {
// find the first fence
int backtickIndex = line.lastIndexOf(CODE_FENCE_BACKTICK);
int tildeIndex = line.lastIndexOf(CODE_FENCE_TILDE);
return backtickIndex > tildeIndex ? CODE_FENCE_TILDE : CODE_FENCE_BACKTICK;
}
else {
// give back whoever has the least amount of occurrences
return backticks > tildes ? CODE_FENCE_TILDE : CODE_FENCE_BACKTICK;
}
}
else if (hasTildeStart) {
return CODE_FENCE_BACKTICK;
}
else if (hasBacktickStart) {
return CODE_FENCE_TILDE;
}
return null;
}
@SuppressWarnings("SameParameterValue")
private static int getOccurenceCount(@NotNull String line, @NotNull Pattern pattern) {
Matcher matcher = pattern.matcher(line);

View File

@@ -65,7 +65,7 @@ public class PsiMarkdownCodeBlockImpl extends CompositePsiElement implements Psi
@Override
public boolean isInline() {
return getFirstChildNode().getTokenType() == JavaDocTokenType.DOC_INLINE_CODE_FENCE;
return getFirstChildNode().getElementType() == JavaDocTokenType.DOC_INLINE_CODE_FENCE;
}
private @Nullable String getLanguageInfo() {

View File

@@ -0,0 +1,3 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Main</span></pre></div><div class='content'>
<pre><code><span style="">@Service<br></span><span style="color:#000080;font-weight:bold;">public&#32;class&#32;</span><span style="">TestService&#32;{}</span></code></pre>
</div><table class='sections'><p></table>

View File

@@ -0,0 +1,8 @@
/**
* <pre><code>
* &#64;Service
* public class TestService {}
* </code></pre>
*/
class Main {
}

View File

@@ -0,0 +1,86 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">InfoGen</span><span style="">&lt;</span><span style="color:#20999d;">K</span><span style="">, </span><span style="color:#20999d;">V</span><span style="">&gt;</span></pre></div><div class='content'>
Hash table based implementation of the <code><span style="">Map</span></code> interface. This
implementation provides all of the optional map operations, and permits
<code><span style="color:#000080;font-weight:bold;">null</span></code> values and the <code><span style="color:#000080;font-weight:bold;">null</span></code> key. (The <code><span style="">HashMap</span></code>
class is roughly equivalent to <code><span style="">Hashtable</span></code>, except that it is
unsynchronized and permits nulls.) This class makes no guarantees as to
the order of the map; in particular, it does not guarantee that the order
will remain constant over time.
<p>This implementation provides constant-time performance for the basic
operations (<code><span style="">get</span></code> and <code><span style="">put</span></code>), assuming the hash function
disperses the elements properly among the buckets. Iteration over
collection views requires time proportional to the "capacity" of the
<code><span style="">HashMap</span></code> instance (the number of buckets) plus its size (the number
of key-value mappings). Thus, it's very important not to set the initial
capacity too high (or the load factor too low) if iteration performance is
important.
<p>An instance of <code><span style="">HashMap</span></code> has two parameters that affect its
performance: <i>initial capacity</i> and <i>load factor</i>. The
<i>capacity</i> is the number of buckets in the hash table, and the initial
capacity is simply the capacity at the time the hash table is created. The
<i>load factor</i> is a measure of how full the hash table is allowed to
get before its capacity is automatically increased. When the number of
entries in the hash table exceeds the product of the load factor and the
current capacity, the hash table is <i>rehashed</i> (that is, internal data
structures are rebuilt) so that the hash table has approximately twice the
number of buckets.
<p>As a general rule, the default load factor (.75) offers a good
tradeoff between time and space costs. Higher values decrease the
space overhead but increase the lookup cost (reflected in most of
the operations of the <code><span style="">HashMap</span></code> class, including
<code><span style="">get</span></code> and <code><span style="">put</span></code>). The expected number of entries in
the map and its load factor should be taken into account when
setting its initial capacity, so as to minimize the number of
rehash operations. If the initial capacity is greater than the
maximum number of entries divided by the load factor, no rehash
operations will ever occur.
<p>If many mappings are to be stored in a <code><span style="">HashMap</span></code>
instance, creating it with a sufficiently large capacity will allow
the mappings to be stored more efficiently than letting it perform
automatic rehashing as needed to grow the table. Note that using
many keys with the same <code><span style="">hashCode()</span></code> is a sure way to slow
down performance of any hash table. To ameliorate impact, when keys
are <a href="psi_element://java.lang.Comparable"><code><span style="color:#0000ff;">Comparable</span></code></a>, this class may use comparison order among
keys to help break ties.
<p><strong>Note that this implementation is not synchronized.</strong>
If multiple threads access a hash map concurrently, and at least one of
the threads modifies the map structurally, it <i>must</i> be
synchronized externally. (A structural modification is any operation
that adds or deletes one or more mappings; merely changing the value
associated with a key that an instance already contains is not a
structural modification.) This is typically accomplished by
synchronizing on some object that naturally encapsulates the map.
If no such object exists, the map should be "wrapped" using the
<a href="psi_element://java.util.Collections#synchronizedMap(java.util.Map)"><code><span style="color:#0000ff;">Collections</span><span style="">.</span><span style="color:#0000ff;">synchronizedMap</span></code></a>
method. This is best done at creation time, to prevent accidental
unsynchronized access to the map:<pre>
Map m = Collections.synchronizedMap(new HashMap(...));</pre>
<p>The iterators returned by all of this class's "collection view methods"
are <i>fail-fast</i>: if the map is structurally modified at any time after
the iterator is created, in any way except through the iterator's own
<code><span style="">remove</span></code> method, the iterator will throw a
<a href="psi_element://java.util.ConcurrentModificationException"><code><span style="color:#0000ff;">ConcurrentModificationException</span></code></a>. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than risking
arbitrary, non-deterministic behavior at an undetermined time in the
future.
<p>Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees in the
presence of unsynchronized concurrent modification. Fail-fast iterators
throw <code><span style="">ConcurrentModificationException</span></code> on a best-effort basis.
Therefore, it would be wrong to write a program that depended on this
exception for its correctness: <i>the fail-fast behavior of iterators
should be used only to detect bugs.</i>
<p>This class is a member of the
<a href="/java.base/java/util/package-summary.html#CollectionsFramework">
Java Collections Framework</a>.
</div><table class='sections'><p><tr><td valign='top' class='section'><p>Since:</td><td valign='top'><p> 1.2</td><tr><td valign='top' class='section'><p>See Also:</td><td valign='top'><p><a href="psi_element://java.lang.Object#hashCode()"><code><span style="color:#0000ff;">Object</span><span style="">.</span><span style="color:#0000ff;">hashCode</span><span style="">()</span></code></a>,<br><a href="psi_element://java.util.Collection"><code><span style="color:#0000ff;">Collection</span></code></a>,<br><a href="psi_element://java.util.Map"><code><span style="color:#0000ff;">Map</span></code></a>,<br><a href="psi_element://java.util.TreeMap"><code><span style="color:#0000ff;">TreeMap</span></code></a>,<br><a href="psi_element://java.util.Hashtable"><code><span style="color:#0000ff;">Hashtable</span></code></a></td><tr><td valign='top' class='section'><p>Author:</td><td valign='top'><p>Doug Lea, Josh Bloch, Arthur van Hoff, Neal Gafter</td><tr><td valign='top' class='section'><p>Type parameters:</td><td valign='top'><code>&lt;<span style="color:#20999d;">K</span>&gt;</code> &ndash; the type of keys maintained by this map <br><code>&lt;<span style="color:#20999d;">V</span>&gt;</code> &ndash; the type of mapped values </td></table>

View File

@@ -0,0 +1,104 @@
import java.util.*;
/**
* Hash table based implementation of the {@code Map} interface. This
* implementation provides all of the optional map operations, and permits
* {@code null} values and the {@code null} key. (The {@code HashMap}
* class is roughly equivalent to {@code Hashtable}, except that it is
* unsynchronized and permits nulls.) This class makes no guarantees as to
* the order of the map; in particular, it does not guarantee that the order
* will remain constant over time.
*
* <p>This implementation provides constant-time performance for the basic
* operations ({@code get} and {@code put}), assuming the hash function
* disperses the elements properly among the buckets. Iteration over
* collection views requires time proportional to the "capacity" of the
* {@code HashMap} instance (the number of buckets) plus its size (the number
* of key-value mappings). Thus, it's very important not to set the initial
* capacity too high (or the load factor too low) if iteration performance is
* important.
*
* <p>An instance of {@code HashMap} has two parameters that affect its
* performance: <i>initial capacity</i> and <i>load factor</i>. The
* <i>capacity</i> is the number of buckets in the hash table, and the initial
* capacity is simply the capacity at the time the hash table is created. The
* <i>load factor</i> is a measure of how full the hash table is allowed to
* get before its capacity is automatically increased. When the number of
* entries in the hash table exceeds the product of the load factor and the
* current capacity, the hash table is <i>rehashed</i> (that is, internal data
* structures are rebuilt) so that the hash table has approximately twice the
* number of buckets.
*
* <p>As a general rule, the default load factor (.75) offers a good
* tradeoff between time and space costs. Higher values decrease the
* space overhead but increase the lookup cost (reflected in most of
* the operations of the {@code HashMap} class, including
* {@code get} and {@code put}). The expected number of entries in
* the map and its load factor should be taken into account when
* setting its initial capacity, so as to minimize the number of
* rehash operations. If the initial capacity is greater than the
* maximum number of entries divided by the load factor, no rehash
* operations will ever occur.
*
* <p>If many mappings are to be stored in a {@code HashMap}
* instance, creating it with a sufficiently large capacity will allow
* the mappings to be stored more efficiently than letting it perform
* automatic rehashing as needed to grow the table. Note that using
* many keys with the same {@code hashCode()} is a sure way to slow
* down performance of any hash table. To ameliorate impact, when keys
* are {@link Comparable}, this class may use comparison order among
* keys to help break ties.
*
* <p><strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access a hash map concurrently, and at least one of
* the threads modifies the map structurally, it <i>must</i> be
* synchronized externally. (A structural modification is any operation
* that adds or deletes one or more mappings; merely changing the value
* associated with a key that an instance already contains is not a
* structural modification.) This is typically accomplished by
* synchronizing on some object that naturally encapsulates the map.
*
* If no such object exists, the map should be "wrapped" using the
* {@link Collections#synchronizedMap Collections.synchronizedMap}
* method. This is best done at creation time, to prevent accidental
* unsynchronized access to the map:<pre>
* Map m = Collections.synchronizedMap(new HashMap(...));</pre>
*
* <p>The iterators returned by all of this class's "collection view methods"
* are <i>fail-fast</i>: if the map is structurally modified at any time after
* the iterator is created, in any way except through the iterator's own
* {@code remove} method, the iterator will throw a
* {@link ConcurrentModificationException}. Thus, in the face of concurrent
* modification, the iterator fails quickly and cleanly, rather than risking
* arbitrary, non-deterministic behavior at an undetermined time in the
* future.
*
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
* presence of unsynchronized concurrent modification. Fail-fast iterators
* throw {@code ConcurrentModificationException} on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness: <i>the fail-fast behavior of iterators
* should be used only to detect bugs.</i>
*
* <p>This class is a member of the
* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
* Java Collections Framework</a>.
*
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
*
* @author Doug Lea
* @author Josh Bloch
* @author Arthur van Hoff
* @author Neal Gafter
* @see Object#hashCode()
* @see Collection
* @see Map
* @see TreeMap
* @see Hashtable
* @since 1.2
*/
class InfoGen<K, V> {
}

View File

@@ -1,2 +1,2 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">MarkdownFeatures</span></pre></div><div class='content'><h1>Title1</h1><h2>Title2</h2><h3>Title 3</h3><p><em>italic</em> <strong>strong</strong> <code>code</code></p><p>Separate paragraph</p> <pre><code><span style="">System.out.println(</span><span style="color:#008000;font-weight:bold;">"Hello&#32;there"</span><span style="">);</span></code></pre>
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">MarkdownFeatures</span></pre></div><div class='content'><h1>Title1</h1><h2>Title2</h2><h3>Title 3</h3><p><em>italic</em> <strong>strong</strong> <code><span style="">code</span></code></p><p>Separate paragraph</p> <pre><code><span style="">System.out.println(</span><span style="color:#008000;font-weight:bold;">"Hello&#32;there"</span><span style="">);</span></code></pre>
</div><table class='sections'><p></table>

View File

@@ -1,3 +1,3 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">MarkdownCodeBlock</span></pre></div><div class='content'><p>Single liner code block:
<code>Hello world</code></p><p>No tags are interpreted inside them
<code>{@link java.lang.String niceLink}</code></p></div><table class='sections'><p></table>
<code><span style="">Hello world</span></code></p><p>No tags are interpreted inside them
<code><span style="">{@link java.lang.String niceLink}</span></code></p></div><table class='sections'><p></table>

View File

@@ -1 +1 @@
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://InlineWithTagsMarkdown"><code><span style="color:#000000;">InlineWithTagsMarkdown</span></code></a></div><div class='definition'><pre><span style="color:#000080;font-weight:bold;">boolean</span>&nbsp;<span style="color:#000000;">foo</span><span style="">(</span><br> <span style="color:#000080;font-weight:bold;">int</span>&nbsp;<span style="color:#000000;">bar</span><br><span style="">)</span></pre></div><table class='sections'><p><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><code><span style="color:#000000;">bar</span></code> &ndash; an int, set to <code>-1</code></td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><em>Some value</em></td></table>
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://InlineWithTagsMarkdown"><code><span style="color:#000000;">InlineWithTagsMarkdown</span></code></a></div><div class='definition'><pre><span style="color:#000080;font-weight:bold;">boolean</span>&nbsp;<span style="color:#000000;">foo</span><span style="">(</span><br> <span style="color:#000080;font-weight:bold;">int</span>&nbsp;<span style="color:#000000;">bar</span><br><span style="">)</span></pre></div><table class='sections'><p><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><code><span style="color:#000000;">bar</span></code> &ndash; an int, set to <code><span style="">-</span><span style="color:#0000ff;">1</span></code></td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><em>Some value</em></td></table>

View File

@@ -1,17 +1,17 @@
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://MarkdownJepExample"><code><span style="color:#000000;">MarkdownJepExample</span></code></a></div><div class='definition'><pre><span style="color:#000080;font-weight:bold;">public</span>&nbsp;<a href="psi_element://java.lang.String"><code><span style="color:#000000;">String</span></code></a>&nbsp;<span style="color:#000000;">longExample</span><span style="">(</span><span style="">)</span></pre></div><div class='content'><p>Returns a hash code value for the object. This method is
supported for the benefit of hash tables such as those provided by
<a href="psi_element://java.util.HashMap"><code><span style="color:#0000ff;">java.util.HashMap</span></code></a>.</p><p>The general contract of <code>hashCode</code> is:</p><ul><li>Whenever it is invoked on the same object more than once during
an execution of a Java application, the <code>hashCode</code> method
<a href="psi_element://java.util.HashMap"><code><span style="color:#0000ff;">java.util.HashMap</span></code></a>.</p><p>The general contract of <code><span style="">hashCode</span></code> is:</p><ul><li>Whenever it is invoked on the same object more than once during
an execution of a Java application, the <code><span style="">hashCode</span></code> method
must consistently return the same integer, provided no information
used in <code>equals</code> comparisons on the object is modified.
used in <code><span style="">equals</span></code> comparisons on the object is modified.
This integer need not remain consistent from one execution of an
application to another execution of the same application.</li><li>If two objects are equal according to the
<a href="psi_element://java.lang.Object#equals(java.lang.Object)"><span style="color:#0000ff;">equals</span></a> method, then calling the
<code>hashCode</code> method on each of the two objects must produce the
<code><span style="">hashCode</span></code> method on each of the two objects must produce the
same integer result.</li><li>It is <em>not</em> required that if two objects are unequal
according to the <a href="psi_element://java.lang.Object#equals(java.lang.Object)"><span style="color:#0000ff;">equals</span></a> method, then
calling the <code>hashCode</code> method on each of the two objects
calling the <code><span style="">hashCode</span></code> method on each of the two objects
must produce distinct integer results. However, the programmer
should be aware that producing distinct integer results for
unequal objects may improve the performance of hash tables.</li></ul></div><table class='sections'><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p>a hash code value for this object.</td><tr><td valign='top' class='section'><p>Implementation<br>Requirements:</td><td valign='top'><p><p>As far as is reasonably practical, the <code>hashCode</code> method defined
by class <code>Object</code> returns distinct integers for distinct objects.</p></td><tr><td valign='top' class='section'><p>See Also:</td><td valign='top'><p><a href="psi_element://java.lang.Object#equals(java.lang.Object)"><code><span style="color:#0000ff;">Object</span><span style="">.</span><span style="color:#0000ff;">equals</span><span style="">(Object)</span></code></a>,<br><a href="psi_element://java.lang.System#identityHashCode(java.lang.Object)"><code><span style="color:#0000ff;">System</span><span style="">.</span><span style="color:#0000ff;">identityHashCode</span></code></a></td></table>
unequal objects may improve the performance of hash tables.</li></ul></div><table class='sections'><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p>a hash code value for this object.</td><tr><td valign='top' class='section'><p>Implementation<br>Requirements:</td><td valign='top'><p><p>As far as is reasonably practical, the <code><span style="">hashCode</span></code> method defined
by class <code><span style="">Object</span></code> returns distinct integers for distinct objects.</p></td><tr><td valign='top' class='section'><p>See Also:</td><td valign='top'><p><a href="psi_element://java.lang.Object#equals(java.lang.Object)"><code><span style="color:#0000ff;">Object</span><span style="">.</span><span style="color:#0000ff;">equals</span><span style="">(Object)</span></code></a>,<br><a href="psi_element://java.lang.System#identityHashCode(java.lang.Object)"><code><span style="color:#0000ff;">System</span><span style="">.</span><span style="color:#0000ff;">identityHashCode</span></code></a></td></table>

View File

@@ -0,0 +1,6 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Test</span></pre></div><div class='content'>
<pre>
Beautiful pre content, inline with one of the tags. This somehow trips dectection for the @code tag.
So now we have a test. But god forbid you put a space at the closing tag.</pre>
<code><span style="">-</span><span style="color:#0000ff;">1</span></code> text inline with the @code tag ?
</div><table class='sections'><p></table>

View File

@@ -0,0 +1,9 @@
/**
* <pre>
* Beautiful pre content, inline with one of the tags. This somehow trips dectection for the @code tag.
* So now we have a test. But god forbid you put a space at the closing tag.</pre>
* {@code -1} text inline with the @code tag ?
*/
class Test {
public String field = null;
}

View File

@@ -205,6 +205,16 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
}
public void testMarkdownInlineCodeBlock() { doTestClass(); }
public void testHashMapCodeTags() {
doTestClass();
}
public void testEscapeHtmlCodesInCodeBlock(){
doTestClass();
}
public void testPreTagLeakBeforeCode() {
doTestClass();
}
public void testRepeatableAnnotations() {
useJava8();

View File

@@ -1871,7 +1871,7 @@ public class Test {
/// Purposefully misaaligned stuff
public class Main {}
""".trimIndent(), """
/// Purposefully misaaligned stuff
/// Purposefully misaaligned stuff
public class Main {
}
""".trimIndent())
@@ -1947,4 +1947,88 @@ public class Test {
}
""".trimIndent())
}
fun testListItemIndentBeingPreserved() {
settings.apply {
WRAP_COMMENTS = true
RIGHT_MARGIN = 120
}
javaSettings.apply {
JD_PRESERVE_LINE_FEEDS = false
}
doTextTest("""
/// This method is
/// supported for the benefit of hash tables such as those provided by
/// [java.util.HashMap].
///
/// The general contract of `hashCode` is:
///
/// - Whenever it is invoked on the same object more than once during
/// an execution of a Java application, the `hashCode` method abusively long line that will force the line feed to be cut nonetheless, what will you do in the situation
/// This integer need not remain consistent from one execution of an
/// application to another execution of the same application.
/// + If two objects are equal according to the
/// [equals][#equals(Object)] method
/// * It is _not_ required that if two objects are unequal
/// according to the [equals][#equals(Object)] method
///
/// @param toto As a tag, it should be brought back to the left
class C {}
""".trimIndent(), """
/// This method is supported for the benefit of hash tables such as those provided by [java.util.HashMap].
///
/// The general contract of `hashCode` is:
///
/// - Whenever it is invoked on the same object more than once during an execution of a Java application, the
/// `hashCode` method abusively long line that will force the line feed to be cut nonetheless, what will you do in the
/// situation This integer need not remain consistent from one execution of an application to another execution of the
/// same application.
/// + If two objects are equal according to the [equals][#equals(Object)] method
/// * It is _not_ required that if two objects are unequal according to the [equals][#equals(Object)] method
///
/// @param toto As a tag, it should be brought back to the left
class C {
}
""".trimIndent())
}
fun testMarkdownConstructsImmuneToWrapping() {
settings.apply {
WRAP_COMMENTS = true
RIGHT_MARGIN = 120
}
javaSettings.apply {
JD_PRESERVE_LINE_FEEDS = false
}
doTextTest("""
/// | Latin | Greek |
/// |-------|-------|
/// | a | alpha |
/// | b | beta |
/// | c | gamma |
///
/// > Nice blockquote
/// - Single list item
/// + Sub element
/// * Another sub element
/// ---
/// # Title, but I have a long text, so loong in fact that it will probably get wrapped. Depends on whether I wrote my code properly. Anyhow, is someone down for a game of Minecraft ?
///
""".trimIndent(), """
/// | Latin | Greek |
/// |-------|-------|
/// | a | alpha |
/// | b | beta |
/// | c | gamma |
///
/// > Nice blockquote
/// - Single list item
/// + Sub element
/// * Another sub element
/// ---
/// # Title, but I have a long text, so loong in fact that it will probably get wrapped. Depends on whether I wrote my code properly. Anyhow, is someone down for a game of Minecraft ?
""".trimIndent())
}
}

View File

@@ -170,7 +170,7 @@ new Gr<caret>oovyDocTest<Integer>()""", """\
def foo() {}
fo<caret>o()
""", "<div class=\"bottom\"><icon src=\"AllIcons.Nodes.Class\">&nbsp;<a href=\"psi_element://_\"><code><span style=\"color:#000000;\">_</span></code></a></div><div class='definition'><pre><a href=\"psi_element://java.lang.Object\"><code><span style=\"color:#000000;\">Object</span></code></a>&nbsp;<span style=\"color:#000000;\">foo</span><span style=\"\">(</span><span style=\"\">)</span></pre></div><div class='content'>\n" +
" <code><span style=\"\">aaa</span><span style=\"\">&#32;bbb</span><span style=\"\">&#32;ccc</span></code>\n" +
" <code><span style=\"\">aaa&#32;bbb&#32;ccc</span></code>\n" +
" </div><table class='sections'></table>"
}