Java: inspection for migration to Markdown documentation comments (IDEA-357191)

GitOrigin-RevId: 94d6c21d713073df58e2f6fb2bbd348a7039b9ce
This commit is contained in:
Bas Leijdekkers
2024-08-08 20:19:46 +00:00
committed by intellij-monorepo-bot
parent 488e4a01bf
commit 91cff4a4f1
8 changed files with 1034 additions and 0 deletions
@@ -2365,6 +2365,9 @@ inspection.deconstruction.can.be.used.display.name=Record pattern can be used
inspection.deconstruction.can.be.used.message=Can be replaced with record pattern
inspection.deconstruction.can.be.used.fix.family.name=Replace with record pattern
markdown.documentation.comments.migration.display.name=Javadoc comment can be Markdown documentation comment
markdown.documentation.comments.migration.fix=Convert to Markdown documentation comment
array.hash.code.fix.family.name=Replace with 'Arrays.hashCode()' call
objects.hash.fix.family.name=Wrap with 'Arrays.hashCode()'
unqualified.static.access.fix.family.name=Qualify static access
@@ -0,0 +1,309 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.migration;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaDocTokenType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.javadoc.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
final class MarkdownDocumentationCommentsMigrationInspection extends BaseInspection {
@Override
protected @NotNull String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message("markdown.documentation.comments.migration.display.name");
}
@Override
protected @NotNull LocalQuickFix buildFix(Object... infos) {
return new MarkdownDocumentationCommentsMigrationFix();
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new MarkdownDocumentationCommentsMigrationVisitor();
}
private static class MarkdownDocumentationCommentsMigrationVisitor extends BaseInspectionVisitor {
@Override
public void visitDocComment(@NotNull PsiDocComment comment) {
super.visitDocComment(comment);
PsiElement child = comment.getFirstChild();
if (!"/**".equals(child.getText())) {
return;
}
registerError(isVisibleHighlight(comment) ? child : comment);
}
}
private static class MarkdownDocumentationCommentsMigrationFix extends PsiUpdateModCommandQuickFix {
public static final TokenSet SKIP_TOKENS = TokenSet.create(JavaDocTokenType.DOC_COMMENT_START, JavaDocTokenType.DOC_COMMENT_END);
@Override
public @NotNull String getFamilyName() {
return InspectionGadgetsBundle.message("markdown.documentation.comments.migration.fix");
}
@Override
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
if (element instanceof PsiDocToken) element = element.getParent();
if (!(element instanceof PsiDocComment)) return;
StringBuilder text = appendCommentText(element, new StringBuilder());
String markdown = convertToMarkdown(text.toString());
String indent = getElementIndent(element);
String[] lines = markdown.split("\n");
StringBuilder result = new StringBuilder(text.length() + (indent.length() + 4) * lines.length);
for (String line : lines) {
if (!result.isEmpty()) {
result.append(indent);
}
result.append("///").append(line).append('\n');
}
Document document = element.getContainingFile().getFileDocument();
int startOffset = element.getTextOffset();
int endOffset = element.getNextSibling() instanceof PsiWhiteSpace whiteSpace
? whiteSpace.getTextOffset() + whiteSpace.getTextLength()
: startOffset + element.getTextLength();
document.replaceString(startOffset, endOffset, result);
}
private static StringBuilder appendCommentText(@NotNull PsiElement element, StringBuilder result) {
for (@NotNull PsiElement child : element.getChildren()) {
if (isDocToken(child, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
continue;
}
else if (child instanceof PsiDocToken token && SKIP_TOKENS.contains(token.getTokenType())) {
continue;
}
else if (child instanceof PsiInlineDocTag inlineDocTag) {
PsiElement nameElement = inlineDocTag.getNameElement();
PsiElement next = nameElement.getNextSibling();
if (next instanceof PsiWhiteSpace && next.getText().contains("\n")) {
result.append("\n ");
}
String name = inlineDocTag.getName();
if ("code".equals(name)) {
handleCodeInlineDocTag(inlineDocTag, result);
}
else if ("link".equals(name)) {
handleLinkInlineDocTag(inlineDocTag, result);
}
else {
handleGenericInlineDocTag(inlineDocTag, result);
}
continue;
}
if (child instanceof PsiDocTag || child instanceof PsiDocTagValue) {
appendCommentText(child, result);
continue;
}
else if (child instanceof PsiWhiteSpace) {
if (!isDocToken(child.getNextSibling(), JavaDocTokenType.DOC_COMMENT_END)) {
String text = child.getText();
if (text.contains("\n")) {
if (!result.isEmpty()) {
result.append("\n");
}
}
else {
result.append(text);
}
}
continue;
}
result.append(child.getText());
}
return result;
}
private static String convertToMarkdown(String html) {
int tag = -1;
boolean endTag = false;
boolean newLine = false;
boolean inList = false;
StringBuilder result = new StringBuilder();
for (int i = 0, length = html.length(); i < length; i++) {
char c = html.charAt(i);
if (tag >= 0) {
if (isLetterOrDigitAscii(c)) {
continue;
}
else if (c == '/') {
if (i == tag + 1) endTag = true;
continue;
}
else if (c == '>') {
String name = html.substring(tag + (endTag ? 2 : 1), (html.charAt(i-1) == '/') ? i - 1 : i);
if ("li".equals(name)) {
if (endTag) {
inList = false;
}
else {
if (" ".equals(result.substring(result.length() - 4))) {
result.delete(result.length() - 4, result.length());
}
result.append(" - ");
inList = true;
}
}
else if ("em".equals(name) || "i".equals(name)) {
result.append('_');
}
else if ("b".equals(name) || "strong".equals(name)) {
result.append("**");
}
else if ("hr".equals(name)) {
result.append("---");
}
else if ("p".equals(name)) {
if (i + 1 < length && html.charAt(i + 1) != '\n') result.append("\n ");
}
else if ("br".equals(name)) {
result.append(" \n");
}
else if ("ul".equals(name)) {
if (endTag) inList = false;
}
else {
result.append(html, tag, i + 1);
}
}
else {
result.append(html, tag, i + 1);
}
tag = -1;
endTag = false;
}
else {
if (c == '\n') {
if (newLine && !(i + 2 < length && html.charAt(i + 2) == '@')) {
continue;
}
result.append(inList ? "\n " : "\n");
newLine = true;
}
else {
if (newLine && inList && c == ' ') continue;
newLine = false;
if (c == '<') {
tag = i;
}
else {
result.append(c);
}
}
}
}
return result.toString();
}
private static boolean isLetterOrDigitAscii(char cur) {
return cur >= 'a' && cur <= 'z' || cur >= 'A' && cur <= 'Z' || cur >= '0' && cur <= '9';
}
private static String getElementIndent(PsiElement element) {
PsiElement leaf = PsiTreeUtil.prevLeaf(element);
if (!(leaf instanceof PsiWhiteSpace)) {
return "";
}
String text = leaf.getText();
final int lineBreak = text.lastIndexOf('\n');
return text.substring(lineBreak + 1);
}
private static void handleGenericInlineDocTag(PsiElement element, StringBuilder result) {
PsiElement[] children = element.getChildren();
if (children.length > 0) {
for (@NotNull PsiElement child : children) {
handleGenericInlineDocTag(child, result);
}
return;
}
if (element instanceof PsiWhiteSpace) {
String text = element.getText();
if (text.contains("\n")) {
result.append("\n ");
}
else {
result.append(text);
}
return;
}
else if (isDocToken(element, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
return;
}
result.append(element.getText());
}
private static void handleCodeInlineDocTag(PsiInlineDocTag inlineDocTag, StringBuilder result) {
result.append('`');
for (PsiElement dataElement : inlineDocTag.getDataElements()) {
if (dataElement instanceof PsiDocToken) {
result.append(dataElement.getText().trim());
}
}
result.append('`');
}
private static void handleLinkInlineDocTag(PsiInlineDocTag inlineDocTag, StringBuilder result) {
result.append('[');
PsiElement[] dataElements = inlineDocTag.getDataElements();
boolean dataFound = false;
for (PsiElement dataElement : dataElements) {
if (dataElement instanceof PsiDocToken) {
String text = dataElement.getText().trim();
if (!text.isEmpty()) {
result.append(text);
dataFound = true;
}
}
}
if (dataFound) result.append("][");
for (PsiElement dataElement : dataElements) {
if (dataElement instanceof PsiDocMethodOrFieldRef) {
for (@NotNull PsiElement refChild : dataElement.getChildren()) {
if (refChild instanceof PsiDocToken) {
result.append(refChild.getText());
}
else if (refChild instanceof PsiDocTagValue) {
for (@NotNull PsiElement valueChild : refChild.getChildren()) {
if (valueChild instanceof PsiWhiteSpace) {
if (valueChild.getText().contains("\n")) {
result.append("\n ");
}
continue;
}
if (isDocToken(valueChild, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) continue;
result.append(valueChild.getText());
}
}
}
}
else if (!(dataElement instanceof PsiDocToken) && !(dataElement instanceof PsiWhiteSpace)) {
result.append(dataElement.getText());
}
}
result.append(']');
}
private static boolean isDocToken(PsiElement element, IElementType tokenType) {
return element instanceof PsiDocToken token && tokenType == token.getTokenType();
}
}
}
@@ -1338,6 +1338,10 @@
key="while.can.be.foreach.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.language.level.specific.issues.and.migration.aids5" enabledByDefault="true" level="WARNING"
implementationClass="com.siyeh.ig.migration.WhileCanBeForeachInspection"/>
<localInspection groupPathKey="group.path.names.java.language.level.specific.issues.and.migration.aids" language="JAVA" shortName="MarkdownDocumentationCommentsMigration" bundle="messages.InspectionGadgetsBundle"
key="markdown.documentation.comments.migration.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.language.level.specific.issues.and.migration.aids23" enabledByDefault="true" level="INFORMATION"
implementationClass="com.siyeh.ig.migration.MarkdownDocumentationCommentsMigrationInspection"/>
<!--group.names.java.language.level.issues-->
<localInspection groupPath="Java" language="JAVA" shortName="AnnotationClass" bundle="messages.InspectionGadgetsBundle" key="annotation.class.display.name"
@@ -0,0 +1,25 @@
<html>
<body>
Reports Javadoc comments that can be converted to Markdown documentation comments.
<p><b>Example:</b></p>
<pre><code>
/**
* For blubbering of the florz.
*
* Similar to {@link com.deeps.Querp querping} class.
*/
class FlorzBlubber {
}
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
/// For blubbering of the florz.
/// Similar to [querping][com.deeps.Querp] class.
class FlorzBlubber {
}
</code></pre>
<!-- tooltip end -->
<p><small>New in 2024.2</small></p>
</body>
</html>
@@ -0,0 +1,327 @@
import java.util.HashMap;
///<caret> test data file
/// ---
/// `System.out.println()`
/// [java.util.ArrayList]
/// [description][java.util.HashMap]
/// @author Bas
public class MarkdownDocumentationCommentsMigration {
/// {@return a hash code value for this object} This method is
/// supported for the benefit of hash tables such as those provided by
/// [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
/// must consistently return the same integer, provided no information
/// used in `equals` 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.
/// - If two objects are equal according to 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
/// 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
/// unequal objects may improve the performance of hash tables.
///
///
/// @implSpec As far as is reasonably practical, the `hashCode` method defined
/// by class `Object` returns distinct integers for distinct objects.
/// @apiNote The [hash][#hash(Object...)] and
/// [hashCode][#hashCode(Object)] methods of
/// [Objects] can be used to help construct simple hash codes.
/// @see Object#equals(Object)
/// @see System#identityHashCode
@Override
public int hashCode() {
return super.hashCode();
}
/// Indicates whether some other object is "equal to" this one.
///
/// The `equals` method implements an equivalence relation
/// on non-null object references:
///
/// - It is _reflexive_: for any non-null reference value
/// `x`, `x.equals(x)` should return
/// `true`.
/// - It is _symmetric_: for any non-null reference values
/// `x` and `y`, `x.equals(y)`
/// should return `true` if and only if
/// `y.equals(x)` returns `true`.
/// - It is _transitive_: for any non-null reference values
/// `x`, `y`, and `z`, if
/// `x.equals(y)` returns `true` and
/// `y.equals(z)` returns `true`, then
/// `x.equals(z)` should return `true`.
/// - It is _consistent_: for any non-null reference values
/// `x` and `y`, multiple invocations of
/// `x.equals(y)` consistently return `true`
/// or consistently return `false`, provided no
/// information used in `equals` comparisons on the
/// objects is modified.
/// - For any non-null reference value `x`,
/// `x.equals(null)` should return `false`.
///
///
/// An equivalence relation partitions the elements it operates on
/// into _equivalence classes_; all the members of an
/// equivalence class are equal to each other. Members of an
/// equivalence class are substitutable for each other, at least
/// for some purposes.
///
/// @param obj the reference object with which to compare.
/// @return `true` if this object is the same as the obj
/// argument; `false` otherwise.
/// @implSpec The `equals` method for class `Object` implements
/// the most discriminating possible equivalence relation on objects;
/// that is, for any non-null reference values `x` and
/// `y`, this method returns `true` if and only
/// if `x` and `y` refer to the same object
/// (`x == y` has the value `true`).
///
/// 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()]
/// 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][#equals(Object,
/// Object)] method implements an equivalence relation
/// on two possibly-null object references.
/// @see #hashCode()
/// @see HashMap
@Override
public boolean equals(final Object obj) {
return super.equals(obj);
}
/// Creates and returns a copy of this object. The precise meaning
/// of "copy" may depend on the class of the object. The general
/// intent is that, for any object `x`, the expression:
/// <blockquote>
/// <pre>
/// x.clone() != x</pre></blockquote>
/// will be true, and that the expression:
/// <blockquote>
/// <pre>
/// x.clone().getClass() == x.getClass()</pre></blockquote>
/// will be `true`, but these are not absolute requirements.
/// While it is typically the case that:
/// <blockquote>
/// <pre>
/// x.clone().equals(x)</pre></blockquote>
/// will be `true`, this is not an absolute requirement.
///
/// By convention, the returned object should be obtained by calling
/// `super.clone`. If a class and all of its superclasses (except
/// `Object`) obey this convention, it will be the case that
/// `x.clone().getClass() == x.getClass()`.
///
/// By convention, the object returned by this method should be independent
/// of this object (which is being cloned). To achieve this independence,
/// it may be necessary to modify one or more fields of the object returned
/// by `super.clone` before returning it. Typically, this means
/// copying any mutable objects that comprise the internal "deep structure"
/// of the object being cloned and replacing the references to these
/// objects with references to the copies. If a class contains only
/// primitive fields or references to immutable objects, then it is usually
/// the case that no fields in the object returned by `super.clone`
/// need to be modified.
///
/// @return a clone of this instance.
/// @throws CloneNotSupportedException if the object's class does not
/// support the `Cloneable` interface. Subclasses
/// that override the `clone` method can also
/// throw this exception to indicate that an instance cannot
/// be cloned.
/// @implSpec The method `clone` for class `Object` performs a
/// specific cloning operation. First, if the class of this object does
/// not implement the interface `Cloneable`, then a
/// `CloneNotSupportedException` is thrown. Note that all arrays
/// are considered to implement the interface `Cloneable` and that
/// the return type of the `clone` method of an array type `T[]`
/// is `T[]` where T is any reference or primitive type.
/// Otherwise, this method creates a new instance of the class of this
/// object and initializes all its fields with exactly the contents of
/// the corresponding fields of this object, as if by assignment; the
/// contents of the fields are not themselves cloned. Thus, this method
/// performs a "shallow copy" of this object, not a "deep copy" operation.
///
/// The class `Object` does not itself implement the interface
/// `Cloneable`, so calling the `clone` method on an object
/// whose class is `Object` will result in throwing an
/// exception at run time.
/// @see Cloneable
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/// {@return a string representation of the object}
///
/// Satisfying this method's contract implies a non-`null`
/// result must be returned.
///
/// @apiNote In general, the
/// `toString` method returns a string that
/// "textually represents" this object. The result should
/// be a concise but informative representation that is easy for a
/// person to read.
/// It is recommended that all subclasses override this method.
/// The string output is not necessarily stable over time or across
/// JVM invocations.
/// @implSpec The `toString` method for class `Object`
/// returns a string consisting of the name of the class of which the
/// object is an instance, the at-sign character ``@`', and
/// the unsigned hexadecimal representation of the hash code of the
/// object. In other words, this method returns a string equal to the
/// value of:
/// {@snippet lang = java:
/// getClass().getName() + '@' + Integer.toHexString(hashCode())
/// }
/// The [Objects.toIdentityString][#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.
@Override
public String toString() {
return super.toString();
}
/// Called by the garbage collector on an object when garbage collection
/// determines that there are no more references to the object.
/// A subclass overrides the `finalize` method to dispose of
/// system resources or to perform other cleanup.
///
/// **When running in a Java virtual machine in which finalization has been
/// disabled or removed, the garbage collector will never call
/// `finalize()`. In a Java virtual machine in which finalization is
/// enabled, the garbage collector might call `finalize` only after an
/// indefinite delay.**
///
/// The general contract of `finalize` is that it is invoked
/// if and when the Java virtual
/// machine has determined that there is no longer any
/// means by which this object can be accessed by any thread that has
/// not yet died, except as a result of an action taken by the
/// finalization of some other object or class which is ready to be
/// finalized. The `finalize` method may take any action, including
/// making this object available again to other threads; the usual purpose
/// of `finalize`, however, is to perform cleanup actions before
/// the object is irrevocably discarded. For example, the finalize method
/// for an object that represents an input/output connection might perform
/// explicit I/O transactions to break the connection before the object is
/// permanently discarded.
///
/// The `finalize` method of class `Object` performs no
/// special action; it simply returns normally. Subclasses of
/// `Object` may override this definition.
///
/// The Java programming language does not guarantee which thread will
/// invoke the `finalize` method for any given object. It is
/// guaranteed, however, that the thread that invokes finalize will not
/// be holding any user-visible synchronization locks when finalize is
/// invoked. If an uncaught exception is thrown by the finalize method,
/// the exception is ignored and finalization of that object terminates.
///
/// After the `finalize` method has been invoked for an object, no
/// further action is taken until the Java virtual machine has again
/// determined that there is no longer any means by which this object can
/// be accessed by any thread that has not yet died, including possible
/// actions by other objects or classes which are ready to be finalized,
/// at which point the object may be discarded.
///
/// The `finalize` method is never invoked more than once by a Java
/// virtual machine for any given object.
///
/// Any exception thrown by the `finalize` method causes
/// the finalization of this object to be halted, but is otherwise
/// ignored.
///
/// @throws Throwable the `Exception` raised by this method
/// @apiNote Classes that embed non-heap resources have many options
/// for cleanup of those resources. The class must ensure that the
/// lifetime of each instance is longer than that of any resource it embeds.
/// [#reachabilityFence] can be used to ensure that
/// objects remain reachable while resources embedded in the object are in use.
///
/// A subclass should avoid overriding the `finalize` method
/// unless the subclass embeds non-heap resources that must be cleaned up
/// before the instance is collected.
/// Finalizer invocations are not automatically chained, unlike constructors.
/// If a subclass overrides `finalize` it must invoke the superclass
/// finalizer explicitly.
/// To guard against exceptions prematurely terminating the finalize chain,
/// the subclass should use a `try-finally` block to ensure
/// `super.finalize()` is always invoked. For example,
/// {@snippet lang = "java":
/// @Override
/// protected void finalize() throws Throwable {
/// try {
/// ... // cleanup subclass state
/// } finally {
/// super.finalize();
/// }
/// }
/// }
/// @jls 12.6 Finalization of Class Instances
/// @see WeakReference
/// @see PhantomReference
/// @deprecated Finalization is deprecated and subject to removal in a future
/// release. The use of finalization can lead to problems with security,
/// performance, and reliability.
/// See <a href="https://openjdk.org/jeps/421">JEP 421</a> for
/// discussion and alternatives.
///
/// Subclasses that override `finalize` to perform cleanup should use
/// alternative cleanup mechanisms and remove the `finalize` method.
/// Use [Cleaner] and
/// [PhantomReference] as safer ways to release resources
/// when an object becomes unreachable. Alternatively, add a `close`
/// method to explicitly release resources, and implement
/// `AutoCloseable` to enable use of the `try`-with-resources
/// statement.
///
/// This method will remain in place until finalizers have been removed from
/// most existing code.
@Override
protected void finalize() throws Throwable {
super.finalize();
}
}
/// Allows an action to retrieve information about the context in which it was invoked.
///
/// **NOTES:**
///
/// - Do not implement, or override platform implementations!
/// Things have got more complex since the introduction of asynchronous action update.
/// If you need to alter the provided data context or create one from a set of data
/// use [CustomizedDataContext] or [com.intellij.openapi.actionSystem.impl.SimpleDataContext] instead, even in tests.
/// These classes are async-ready, optionally support [com.intellij.openapi.util.UserDataHolder],
/// and run [com.intellij.ide.impl.dataRules.GetDataRule] rules.
/// - Do not to confuse [DataProvider] with [DataContext].
/// A [DataContext] is usually provided by the platform with [DataProvider]s as its building blocks.
/// For example, a node in a tree view could be a [DataProvider] but not a [DataContext].
///
///
/// @see DataKey
/// @see DataProvider
/// @see UiDataProvider
/// @see AnActionEvent#getDataContext()
/// @see com.intellij.ide.DataManager#getDataContext(Component)
/// @see com.intellij.openapi.actionSystem.CommonDataKeys
/// @see com.intellij.openapi.actionSystem.LangDataKeys
/// @see com.intellij.openapi.actionSystem.PlatformDataKeys
/// @see com.intellij.openapi.actionSystem.PlatformCoreDataKeys
/// @see com.intellij.openapi.actionSystem.CustomizedDataContext
/// @see com.intellij.openapi.actionSystem.impl.SimpleDataContext
interface Nothing {}
@@ -0,0 +1,342 @@
import java.util.HashMap;
<warning descr="Javadoc comment can be Markdown documentation comment">/**<caret></warning>
* test data file
* <hr>
* {@code System.out.println()}
* {@link java.util.ArrayList}
* {@link java.util.HashMap description}
* @author Bas
*/
public class MarkdownDocumentationCommentsMigration {
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* {@return a hash code value for this object} This method is
* supported for the benefit of hash tables such as those provided by
* {@link HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} 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>If two objects are equal according to the {@link
* #equals(Object) equals} method, then calling the {@code
* hashCode} method on each of the two objects must produce the
* same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link #equals(Object) equals} method, then
* calling the {@code 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
* unequal objects may improve the performance of hash tables.
* </ul>
*
* @implSpec As far as is reasonably practical, the {@code hashCode} method defined
* by class {@code Object} returns distinct integers for distinct objects.
* @apiNote The {@link Objects#hash(Object...) hash} and {@link
* Objects#hashCode(Object) hashCode} methods of {@link
* Objects} can be used to help construct simple hash codes.
* @see Object#equals(Object)
* @see System#identityHashCode
*/
@Override
public int hashCode() {
return super.hashCode();
}
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* <ul>
* <li>It is <i>reflexive</i>: for any non-null reference value
* {@code x}, {@code x.equals(x)} should return
* {@code true}.
* <li>It is <i>symmetric</i>: for any non-null reference values
* {@code x} and {@code y}, {@code x.equals(y)}
* should return {@code true} if and only if
* {@code y.equals(x)} returns {@code true}.
* <li>It is <i>transitive</i>: for any non-null reference values
* {@code x}, {@code y}, and {@code z}, if
* {@code x.equals(y)} returns {@code true} and
* {@code y.equals(z)} returns {@code true}, then
* {@code x.equals(z)} should return {@code true}.
* <li>It is <i>consistent</i>: for any non-null reference values
* {@code x} and {@code y}, multiple invocations of
* {@code x.equals(y)} consistently return {@code true}
* or consistently return {@code false}, provided no
* information used in {@code equals} comparisons on the
* objects is modified.
* <li>For any non-null reference value {@code x},
* {@code x.equals(null)} should return {@code false}.
* </ul>
*
* <p>
* An equivalence relation partitions the elements it operates on
* into <i>equivalence classes</i>; all the members of an
* equivalence class are equal to each other. Members of an
* equivalence class are substitutable for each other, at least
* for some purposes.
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @implSpec The {@code equals} method for class {@code Object} implements
* the most discriminating possible equivalence relation on objects;
* that is, for any non-null reference values {@code x} and
* {@code y}, this method returns {@code true} if and only
* if {@code x} and {@code y} refer to the same object
* ({@code x == y} has the value {@code true}).
* <p>
* 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 {@link #hashCode() hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
* <p>The two-argument {@link Objects#equals(Object,
* Object) Objects.equals} method implements an equivalence relation
* on two possibly-null object references.
* @see #hashCode()
* @see HashMap
*/
@Override
public boolean equals(final Object obj) {
return super.equals(obj);
}
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* Creates and returns a copy of this object. The precise meaning
* of "copy" may depend on the class of the object. The general
* intent is that, for any object {@code x}, the expression:
* <blockquote>
* <pre>
* x.clone() != x</pre></blockquote>
* will be true, and that the expression:
* <blockquote>
* <pre>
* x.clone().getClass() == x.getClass()</pre></blockquote>
* will be {@code true}, but these are not absolute requirements.
* While it is typically the case that:
* <blockquote>
* <pre>
* x.clone().equals(x)</pre></blockquote>
* will be {@code true}, this is not an absolute requirement.
* <p>
* By convention, the returned object should be obtained by calling
* {@code super.clone}. If a class and all of its superclasses (except
* {@code Object}) obey this convention, it will be the case that
* {@code x.clone().getClass() == x.getClass()}.
* <p>
* By convention, the object returned by this method should be independent
* of this object (which is being cloned). To achieve this independence,
* it may be necessary to modify one or more fields of the object returned
* by {@code super.clone} before returning it. Typically, this means
* copying any mutable objects that comprise the internal "deep structure"
* of the object being cloned and replacing the references to these
* objects with references to the copies. If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by {@code super.clone}
* need to be modified.
*
* @return a clone of this instance.
* @throws CloneNotSupportedException if the object's class does not
* support the {@code Cloneable} interface. Subclasses
* that override the {@code clone} method can also
* throw this exception to indicate that an instance cannot
* be cloned.
* @implSpec The method {@code clone} for class {@code Object} performs a
* specific cloning operation. First, if the class of this object does
* not implement the interface {@code Cloneable}, then a
* {@code CloneNotSupportedException} is thrown. Note that all arrays
* are considered to implement the interface {@code Cloneable} and that
* the return type of the {@code clone} method of an array type {@code T[]}
* is {@code T[]} where T is any reference or primitive type.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
* contents of the fields are not themselves cloned. Thus, this method
* performs a "shallow copy" of this object, not a "deep copy" operation.
* <p>
* The class {@code Object} does not itself implement the interface
* {@code Cloneable}, so calling the {@code clone} method on an object
* whose class is {@code Object} will result in throwing an
* exception at run time.
* @see Cloneable
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* {@return a string representation of the object}
* <p>
* Satisfying this method's contract implies a non-{@code null}
* result must be returned.
*
* @apiNote In general, the
* {@code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* The string output is not necessarily stable over time or across
* JVM invocations.
* @implSpec The {@code toString} method for class {@code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{@code @}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* {@snippet lang = java:
* getClass().getName() + '@' + Integer.toHexString(hashCode())
*}
* The {@link Objects#toIdentityString(Object)
* Objects.toIdentityString} method returns the string for an
* object equal to the string that would be returned if neither
* the {@code toString} nor {@code hashCode} methods were
* overridden by the object's class.
*/
@Override
public String toString() {
return super.toString();
}
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* Called by the garbage collector on an object when garbage collection
* determines that there are no more references to the object.
* A subclass overrides the {@code finalize} method to dispose of
* system resources or to perform other cleanup.
* <p>
* <b>When running in a Java virtual machine in which finalization has been
* disabled or removed, the garbage collector will never call
* {@code finalize()}. In a Java virtual machine in which finalization is
* enabled, the garbage collector might call {@code finalize} only after an
* indefinite delay.</b>
* <p>
* The general contract of {@code finalize} is that it is invoked
* if and when the Java virtual
* machine has determined that there is no longer any
* means by which this object can be accessed by any thread that has
* not yet died, except as a result of an action taken by the
* finalization of some other object or class which is ready to be
* finalized. The {@code finalize} method may take any action, including
* making this object available again to other threads; the usual purpose
* of {@code finalize}, however, is to perform cleanup actions before
* the object is irrevocably discarded. For example, the finalize method
* for an object that represents an input/output connection might perform
* explicit I/O transactions to break the connection before the object is
* permanently discarded.
* <p>
* The {@code finalize} method of class {@code Object} performs no
* special action; it simply returns normally. Subclasses of
* {@code Object} may override this definition.
* <p>
* The Java programming language does not guarantee which thread will
* invoke the {@code finalize} method for any given object. It is
* guaranteed, however, that the thread that invokes finalize will not
* be holding any user-visible synchronization locks when finalize is
* invoked. If an uncaught exception is thrown by the finalize method,
* the exception is ignored and finalization of that object terminates.
* <p>
* After the {@code finalize} method has been invoked for an object, no
* further action is taken until the Java virtual machine has again
* determined that there is no longer any means by which this object can
* be accessed by any thread that has not yet died, including possible
* actions by other objects or classes which are ready to be finalized,
* at which point the object may be discarded.
* <p>
* The {@code finalize} method is never invoked more than once by a Java
* virtual machine for any given object.
* <p>
* Any exception thrown by the {@code finalize} method causes
* the finalization of this object to be halted, but is otherwise
* ignored.
*
* @throws Throwable the {@code Exception} raised by this method
* @apiNote Classes that embed non-heap resources have many options
* for cleanup of those resources. The class must ensure that the
* lifetime of each instance is longer than that of any resource it embeds.
* {@link Reference#reachabilityFence} can be used to ensure that
* objects remain reachable while resources embedded in the object are in use.
* <p>
* A subclass should avoid overriding the {@code finalize} method
* unless the subclass embeds non-heap resources that must be cleaned up
* before the instance is collected.
* Finalizer invocations are not automatically chained, unlike constructors.
* If a subclass overrides {@code finalize} it must invoke the superclass
* finalizer explicitly.
* To guard against exceptions prematurely terminating the finalize chain,
* the subclass should use a {@code try-finally} block to ensure
* {@code super.finalize()} is always invoked. For example,
* {@snippet lang = "java":
* @Override
* protected void finalize() throws Throwable {
* try {
* <error descr="Unexpected token">...</error> // cleanup subclass state
* } finally {
* super.finalize();
* }
* }
*}
* @jls 12.6 Finalization of Class Instances
* @see WeakReference
* @see PhantomReference
* @deprecated Finalization is deprecated and subject to removal in a future
* release. The use of finalization can lead to problems with security,
* performance, and reliability.
* See <a href="https://openjdk.org/jeps/421">JEP 421</a> for
* discussion and alternatives.
* <p>
* Subclasses that override {@code finalize} to perform cleanup should use
* alternative cleanup mechanisms and remove the {@code finalize} method.
* Use {@link Cleaner} and
* {@link PhantomReference} as safer ways to release resources
* when an object becomes unreachable. Alternatively, add a {@code close}
* method to explicitly release resources, and implement
* {@code AutoCloseable} to enable use of the {@code try}-with-resources
* statement.
* <p>
* This method will remain in place until finalizers have been removed from
* most existing code.
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
}
}
<warning descr="Javadoc comment can be Markdown documentation comment">/**</warning>
* Allows an action to retrieve information about the context in which it was invoked.
* <p/>
* <b>NOTES:</b>
* <ul>
* <li>Do not implement, or override platform implementations!
* Things have got more complex since the introduction of asynchronous action update.
* If you need to alter the provided data context or create one from a set of data
* use {@link CustomizedDataContext} or {@link com.intellij.openapi.actionSystem.impl.SimpleDataContext} instead, even in tests.
* These classes are async-ready, optionally support {@link com.intellij.openapi.util.UserDataHolder},
* and run {@link com.intellij.ide.impl.dataRules.GetDataRule} rules.</li>
* <li>Do not to confuse {@link DataProvider} with {@link DataContext}.
* A {@link DataContext} is usually provided by the platform with {@link DataProvider}s as its building blocks.
* For example, a node in a tree view could be a {@link DataProvider} but not a {@link DataContext}.</li>
* </ul>
*
* @see DataKey
* @see DataProvider
* @see UiDataProvider
* @see AnActionEvent#getDataContext()
* @see com.intellij.ide.DataManager#getDataContext(Component)
* @see com.intellij.openapi.actionSystem.CommonDataKeys
* @see com.intellij.openapi.actionSystem.LangDataKeys
* @see com.intellij.openapi.actionSystem.PlatformDataKeys
* @see com.intellij.openapi.actionSystem.PlatformCoreDataKeys
* @see com.intellij.openapi.actionSystem.CustomizedDataContext
* @see com.intellij.openapi.actionSystem.impl.SimpleDataContext
*/
interface Nothing {}
@@ -0,0 +1,23 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.migration;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightJavaInspectionTestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class MarkdownDocumentationCommentsMigrationInspectionTest extends LightJavaInspectionTestCase {
public void testMarkdownDocumentationCommentsMigration() {
doTest();
checkQuickFixAll();
}
@Override
protected @Nullable InspectionProfileEntry getInspection() {
return new MarkdownDocumentationCommentsMigrationInspection();
}
}
@@ -212,6 +212,7 @@ group.names.language.level.specific.issues.and.migration.aids14=Java 14
group.names.language.level.specific.issues.and.migration.aids15=Java 15
group.names.language.level.specific.issues.and.migration.aids16=Java 16
group.names.language.level.specific.issues.and.migration.aids21=Java 21
group.names.language.level.specific.issues.and.migration.aids23=Java 23
group.names.javabeans.issues=JavaBeans issues
group.names.inheritance.issues=Inheritance issues
group.names.data.flow.issues=Data flow