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 {} /** * 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