diff --git a/java/java-analysis-impl/src/com/siyeh/ig/migration/MarkdownDocumentationCommentsMigrationInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/migration/MarkdownDocumentationCommentsMigrationInspection.java
index 2dcd8ece34e2..f622108cba46 100644
--- a/java/java-analysis-impl/src/com/siyeh/ig/migration/MarkdownDocumentationCommentsMigrationInspection.java
+++ b/java/java-analysis-impl/src/com/siyeh/ig/migration/MarkdownDocumentationCommentsMigrationInspection.java
@@ -118,7 +118,7 @@ public final class MarkdownDocumentationCommentsMigrationInspection extends Base
}
String name = inlineDocTag.getName();
if ("code".equals(name)) handleCode(inlineDocTag, result);
- else if ("link".equals(name)) handleLink(inlineDocTag, result);
+ else if ("link".equals(name) || "linkplain".equals(name)) handleLink(inlineDocTag, result);
else handleInlineDocTag(inlineDocTag, result);
}
else if (child instanceof PsiDocParamRef) {
@@ -218,47 +218,67 @@ public final class MarkdownDocumentationCommentsMigrationInspection extends Base
}
private static void handleLink(PsiInlineDocTag inlineDocTag, StringBuilder result) {
- result.append('[');
+ boolean isPlain = inlineDocTag.getName().equals("linkplain");
PsiElement[] dataElements = inlineDocTag.getDataElements();
- boolean dataFound = false;
+ StringBuilder referenceBuilder = new StringBuilder();
+ StringBuilder labelBuilder = null;
+
+ // Extract label (if available)
for (PsiElement dataElement : dataElements) {
if (dataElement instanceof PsiDocToken) {
- String text = dataElement.getText();
+ String labelText = dataElement.getText();
// Remove the mandatory space
- if (!dataFound) text = text.stripLeading();
- if (!text.isBlank()) {
- result.append(text);
- dataFound = true;
+ if (labelBuilder == null) labelText = labelText.stripLeading();
+ if (!labelText.isBlank()) {
+ if (labelBuilder == null) labelBuilder = new StringBuilder();
+
+ labelBuilder.append(labelText);
}
}
}
- if (dataFound) result.append("][");
+
+ // Extract references
for (PsiElement dataElement : dataElements) {
if (dataElement instanceof PsiDocMethodOrFieldRef) {
for (@NotNull PsiElement refChild : dataElement.getChildren()) {
if (refChild instanceof PsiDocToken) {
- result.append(refChild.getText());
+ referenceBuilder.append(refChild.getText());
}
else if (refChild instanceof PsiDocTagValue) {
for (@NotNull PsiElement valueChild : refChild.getChildren()) {
if (valueChild instanceof PsiWhiteSpace) {
- result.append(valueChild.getText().contains("\n") ? '\n' : valueChild.getText());
+ referenceBuilder.append(valueChild.getText().contains("\n") ? '\n' : valueChild.getText());
}
else if (!isDocToken(valueChild, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
- result.append(valueChild.getText());
+ referenceBuilder.append(valueChild.getText());
}
}
}
else {
- result.append(refChild.getText());
+ referenceBuilder.append(refChild.getText());
}
}
}
else if (!(dataElement instanceof PsiDocToken) && !(dataElement instanceof PsiWhiteSpace)) {
- result.append(dataElement.getText());
+ referenceBuilder.append(dataElement.getText());
}
}
- result.append(']');
+
+ // When a @linkplain tag is without a label, use the reference as one, otherwise the Markdown version mimics the @link tag
+ if(isPlain && labelBuilder == null && !referenceBuilder.isEmpty()) {
+ labelBuilder = referenceBuilder;
+ }
+
+ if (labelBuilder != null) {
+ result.append(!isPlain ? "[" : '[').append(labelBuilder).append(!isPlain ? "]" : ']');
+ }
+ if (!referenceBuilder.isEmpty()) {
+ result.append('[')
+ .append(referenceBuilder.toString()
+ .replace("[", "\\[")
+ .replace("]", "\\]"))
+ .append(']');
+ }
}
}
@@ -414,6 +434,7 @@ public final class MarkdownDocumentationCommentsMigrationInspection extends Base
// Remove consecutive newlines and space which is before the last line
String cleanedText = MULTI_LINE_BREAK.matcher(node.nodeValue()).replaceAll("");
cleanedText = cleanedText
+ .replace("~", "\\~")
.replace("`", "\\`")
.replace("_", "\\_")
.replace("*", "\\*");
diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.after.java b/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.after.java
index 6d99dbcbdf22..094fa4109b4d 100644
--- a/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.after.java
+++ b/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.after.java
@@ -6,7 +6,7 @@ import java.util.HashMap;
/// ___
/// `System.out.println()`
/// [java.util.ArrayList]
-/// [description][java.util.HashMap]
+/// [`description`][java.util.HashMap]
/// @author Bas
public class MarkdownDocumentationCommentsMigration {
/// {@return a hash code value for this object} This method is
@@ -22,11 +22,11 @@ public class MarkdownDocumentationCommentsMigration {
/// 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, then calling the
+ /// [`equals`][#equals(Object)] method, then calling the
/// `hashCode` method on each of the two objects must produce the
/// same integer result.
/// - It is _not_ required that if two objects are unequal
- /// according to the [equals][#equals(Object)] method, then
+ /// according to the [`equals`][#equals(Object)] method, then
/// calling the `hashCode` method on each of the two objects
/// must produce distinct integer results. However, the programmer
/// should be aware that producing distinct integer results for
@@ -34,8 +34,8 @@ public class MarkdownDocumentationCommentsMigration {
///
/// @implSpec As far as is reasonably practical, the `hashCode` method defined
/// by class `Object` returns distinct integers for distinct objects.
- /// @apiNote The [hash][Objects#hash(Object...)] and
- /// [hashCode][Objects#hashCode(Object)] methods of
+ /// @apiNote The [`hash`][Objects#hash(Object...)] and
+ /// [`hashCode`][Objects#hashCode(Object)] methods of
/// [Objects] can be used to help construct simple hash codes.
/// @see Object#equals(Object)
/// @see System#identityHashCode
@@ -88,12 +88,12 @@ public class MarkdownDocumentationCommentsMigration {
///
/// In other words, under the reference equality equivalence
/// relation, each equivalence class only has a single element.
- /// @apiNote It is generally necessary to override the [hashCode][#hashCode()]
+ /// @apiNote It is generally necessary to override the [`hashCode`][#hashCode()]
/// method whenever this method is overridden, so as to maintain the
/// general contract for the `hashCode` method, which states
/// that equal objects must have equal hash codes.
///
- /// The two-argument [Objects.equals][Objects#equals(Object,
+ /// The two-argument [`Objects.equals`][Objects#equals(Object,
/// Object)] method implements an equivalence relation
/// on two possibly-null object references.
/// @see #hashCode()
@@ -190,7 +190,7 @@ public class MarkdownDocumentationCommentsMigration {
/// {@snippet lang = java:
/// getClass().getName() + '@' + Integer.toHexString(hashCode())
/// }
- /// The [Objects.toIdentityString][Objects#toIdentityString(Object)] method returns the string for an
+ /// The [`Objects.toIdentityString`][Objects#toIdentityString(Object)] method returns the string for an
/// object equal to the string that would be returned if neither
/// the `toString` nor `hashCode` methods were
/// overridden by the object's class.
@@ -364,6 +364,10 @@ final class LookupWithIndentsBuilder {
/// `One Sheep,
/// Two Sheeps,
/// ...zzz`
+/// [String][String]
+///
+/// [I am a string, but with a label][String]
+/// [String#copyValueOf(char[])][String#copyValueOf(char\[\])]
///
/// `Single line code block with html tag`
///
@@ -438,12 +442,12 @@ class IntendedLists{
/// lines.
/// ](https://openjdk.org/jeps/467)
///
-/// Link to a type and insert [a line break here][java.time.OffsetDateTime]
+/// Link to a type and insert [`a line break here`][java.time.OffsetDateTime]
class OhMyLinks {}
/// I like my \*asteriks\* and \_underscores\_.
///
-/// And let's not forget about my friend the \`backticks\` !
+/// And let's not forget about my friend the \`backticks\` (and \~\~\~squigly lines\~\~\~) !
///
/// Some fun things include:
/// \## Title like structs
@@ -492,7 +496,7 @@ class Matcher {
/// captured during the previous match: Each occurrence of
/// `${`_name_`}` or `$`_g_
/// will be replaced by the result of evaluating the corresponding
- /// [group(name)][#group(String)] or [group(g)][#group(int)]
+ /// [`group(name)`][#group(String)] or [`group(g)`][#group(int)]
/// respectively. For `$`_g_,
/// the first number after the `$` is always treated as part of
/// the group reference. Subsequent numbers are incorporated into g if
@@ -512,7 +516,7 @@ class Matcher {
/// string.
///
/// This method is intended to be used in a loop together with the
- /// [appendTail][#appendTail(StringBuffer)] and [find][#find()]
+ /// [`appendTail`][#appendTail(StringBuffer)] and [`find`][#find()]
/// methods. The following code, for example, writes `one dog two dogs
/// in the yard` to the standard-output stream:
///
diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.java b/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.java
index cc4af12a5cf7..20949eeaa890 100644
--- a/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.java
+++ b/java/java-tests/testData/ig/com/siyeh/igtest/migration/markdown_documentation_comments_migration/MarkdownDocumentationCommentsMigration.java
@@ -387,6 +387,13 @@ final class LookupWithIndentsBuilder {
*
* Two Sheeps,
* ...zzz}
+ *
+ * {@linkplain String}
+ *
+ * {@linkplain String I am a string, but with a label}
+ *
+ * {@linkplain String#copyValueOf(char[])}
+ *
*
* Single line code block with html tag
*
@@ -483,7 +490,7 @@ class OhMyLinks {}
- * And let's not forget about my friend the `backticks` !
+ * And let's not forget about my friend the `backticks` (and ~~~squigly lines~~~) !
*
* Some fun things include:
* ## Title like structs