String. */
+ // fix@qf2 {{Convert to Javadoc comment}}
+ // edit@qf2 [[sc=4;ec=4]] {{*}}
+ public String displayName() {
+ return name;
+ }
+
+ /** Returns the display name as String. */
+ public String documentedDisplayName() {
+ return name;
+ }
+
+ interface Repository {
+ // Noncompliant@+1 [[quickfixes=qf3]]
+ // Loads the entity. {@link Entity} */
+ // fix@qf3 {{Convert to Javadoc comment}}
+ // edit@qf3 [[sc=5;ec=7]] {{/**}}
+ Entity load(String id);
+
+ /** Loads the entity. {@link Entity} */
+ Entity documentedLoad(String id);
+
+ // Noncompliant@+1
+ // Loads with trailing space. {@link Entity} */
+ Entity loadWithTrailingSpace(String id);
+ }
+
+ // Noncompliant@+1
+ /* {@link AlmostJavadocCheckSample} */
+ static class Nested {}
+
+ /** {@link AlmostJavadocCheckSample} */
+ static class DocumentedNested {}
+
+ // Noncompliant@+1
+ /* @since 1.0 */
+ int version;
+
+ /** @since 1.0 */
+ int documentedVersion;
+
+ enum Kind {
+ // Noncompliant@+1
+ /* Foo bar. */
+ FOO,
+ /** Foo bar. */
+ BAR
+ }
+
+ /* Regular commentary without tags. */
+ void undocumentedOnPurpose() {
+ }
+
+ // Regular line comment with {@link tags} is not almost-Javadoc
+ void lineCommentWithoutTerminator() {
+ }
+
+ /* returns 0 on success */
+ int noTagBecauseReturnIsAWord() {
+ return 0;
+ }
+
+ /* support@param.org is an email, not a Javadoc tag */
+ void emailLooksLikeTag() {
+ }
+
+ /* @Override is a Java annotation mentioned in a comment */
+ void annotationMention() {
+ }
+
+ /* Listok. */
+String status() {
+ return "ok";
+}
diff --git a/java-checks/src/main/java/org/sonar/java/checks/AlmostJavadocCheck.java b/java-checks/src/main/java/org/sonar/java/checks/AlmostJavadocCheck.java
new file mode 100644
index 00000000000..dbb292499df
--- /dev/null
+++ b/java-checks/src/main/java/org/sonar/java/checks/AlmostJavadocCheck.java
@@ -0,0 +1,186 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.java.checks;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.sonar.check.Rule;
+import org.sonar.java.ast.visitors.PublicApiChecker;
+import org.sonar.java.checks.helpers.QuickFixHelper;
+import org.sonar.java.reporting.AnalyzerMessage;
+import org.sonar.java.reporting.JavaQuickFix;
+import org.sonar.java.reporting.JavaTextEdit;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.location.Position;
+import org.sonar.plugins.java.api.tree.ClassTree;
+import org.sonar.plugins.java.api.tree.CompilationUnitTree;
+import org.sonar.plugins.java.api.tree.SyntaxToken;
+import org.sonar.plugins.java.api.tree.SyntaxTrivia;
+import org.sonar.plugins.java.api.tree.SyntaxTrivia.CommentKind;
+import org.sonar.plugins.java.api.tree.Tree;
+import org.sonar.plugins.java.api.tree.VariableTree;
+
+@Rule(key = "S9355")
+public class AlmostJavadocCheck extends IssuableSubscriptionVisitor {
+
+ static final String MESSAGE = "This comment contains Javadoc or HTML tags, but isn't started with a double asterisk (/**); is it meant to be Javadoc?";
+
+ private static final Pattern CLOSING_HTML = Pattern.compile("(?:em|b|a|strong|i|pre|code)>");
+ private static final Pattern AT_TAG = Pattern.compile("(? JAVADOC_TAGS = Set.of(
+ "@author", "@code", "@deprecated", "@docRoot", "@exception", "@inheritDoc",
+ "@link", "@linkplain", "@literal", "@param", "@return", "@see", "@serial",
+ "@serialData", "@serialField", "@since", "@snippet", "@throws", "@value", "@version");
+
+ @Override
+ public ListA documentation comment must start with /**. A regular comment that contains Javadoc tags or HTML documentation tags, and that sits
+immediately above a declaration, is ignored by the Javadoc tool, so the following declaration stays undocumented.
The Javadoc tool recognizes documentation comments that start with /** and that are placed immediately before a class, interface,
+constructor, method, field, or enum constant. A comment that starts with /* or // in that position is ordinary
+commentary.
When such a comment contains Javadoc tags such as @param, @return, or {@link}, or HTML documentation tags
+such as </code> or </em>, it is almost always intended to be Javadoc. Because it is not a documentation comment,
+those tags never attach to the following declaration. Readers and generated API docs then miss the contract that the author already wrote.
Start the comment with /** so the tags document the following declaration.
This rule does not raise an issue when:
+</em>, </b>,
+ </a>, </strong>, </i>, </pre>, or </code>.
+public class MathUtils {
+ /* // Noncompliant: not a documentation comment, so these tags are ignored
+ * Computes the factorial of a positive integer.
+ * @param n the number to compute factorial for
+ * @return the factorial of n
+ */
+ public long factorial(int n) {
+ return (n <= 1) ? 1 : n * factorial(n - 1);
+ }
+}
+
+
+public class MathUtils {
+ /**
+ * Computes the factorial of a positive integer.
+ * @param n the number to compute factorial for
+ * @return the factorial of n
+ */
+ public long factorial(int n) {
+ return (n <= 1) ? 1 : n * factorial(n - 1);
+ }
+}
+
+
+public class Names {
+ /* Returns the display name as <code>String</code>. */ // Noncompliant: HTML documentation tags in a regular block comment
+ public String displayName() {
+ return name;
+ }
+}
+
+
+public class Names {
+ /** Returns the display name as <code>String</code>. */
+ public String displayName() {
+ return name;
+ }
+}
+
+
+interface Repository {
+ // Loads the entity. {@link Entity} */ // Noncompliant: line comment is not started with /**
+ Entity load(String id);
+}
+
+
+interface Repository {
+ /** Loads the entity. {@link Entity} */
+ Entity load(String id);
+}
+
+