Repository: scalameta/scalameta
Pull request #2541 (2022-01-04 07:41:21)

ScaladocParser: handle `@usecase` as special case
Let's handle cases where label is expected but description is not, by reading in the entire tag line as label. This adds required handling to @usecase which must be formatted all on one line.


Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScaladocParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScaladocParser.scala
index cc87ce302..4ad66b62c 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScaladocParser.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScaladocParser.scala
@@ -135,13 +135,17 @@ object ScaladocParser {
 
   private def tagParser[_: P]: P[Tag] = P {
     def label = P((nl ~ !nextPartParser()).? ~ hspaces0 ~ wordParser)
+    // special case: @usecase takes a single code line, on the same line
+    def labelInline = P(hspaces0 ~ (!nl ~ AnyChar).rep(1).!.map(Word))
     def desc = P {
       (textParser().? ~ embeddedTermsParser())
         .map { case (x, terms) => x.fold(terms)(_ +: terms) }
     }
     hspaces0 ~ ("@" ~ labelParser).!.flatMap { tag =>
       val tagType = TagType.getTag(tag)
-      def labelOpt = if (tagType.hasLabel) label.map(x => Some(x)) else Pass(None)
+      def labelOpt =
+        if (!tagType.hasLabel) Pass(None)
+        else (if (tagType.optDesc) label else labelInline).map(x => Some(x))
       def descOpt = if (tagType.optDesc) desc else Pass(Nil)
       (labelOpt ~ descOpt).map { case (label, desc) => Tag(tagType, label, desc) }
     }
diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/Scaladoc.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/Scaladoc.scala
index 36fcaa38d..36c55bb44 100644
--- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/Scaladoc.scala
+++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/Scaladoc.scala
@@ -164,7 +164,7 @@ object Scaladoc {
      * Provide a simplified method definition for when the full method definition is too complex
      * or noisy
      */
-    case object UseCase extends Base("@usecase")
+    case object UseCase extends Base("@usecase", hasLabel = true, optDesc = false)
 
     /* Member grouping tags */
 


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/ScaladocParserSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/ScaladocParserSuite.scala
index 23172af43..48ee6f837 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/ScaladocParserSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/ScaladocParserSuite.scala
@@ -1213,7 +1213,7 @@ class ScaladocParserSuite extends FunSuite {
     // Inherit doc does not merge
     parsedTags.foreach { // check label
       case Tag(t, label, _) if t.hasLabel =>
-        val expected = if (t.optDesc) "TestLabel" else "Test"
+        val expected = if (t.optDesc) "TestLabel" else "Test Label"
         assertEquals(label, Some(Word(expected)))
       case _ =>
     }
@@ -1360,8 +1360,7 @@ class ScaladocParserSuite extends FunSuite {
           Seq(
             Paragraph(
               Seq(
-                Tag(TagType.Version, Some(Word("1.0"))),
-                Text(Seq(Word("foo"), Word("bar"))),
+                Tag(TagType.Version, Some(Word("1.0 foo bar"))),
                 Tag(
                   TagType.Since,
                   Some(Word("1.0")),
@@ -1403,6 +1402,24 @@ class ScaladocParserSuite extends FunSuite {
     )
   }
 
+  test("parse usecase tags") {
+    assertEquals(
+      parseString(
+        s"""
+         /**
+          * @usecase foo bar
+          * baz qux
+          */
+         """
+      ),
+      Option {
+        val label = Some(Word("foo bar"))
+        val rest = Seq(Text(Seq(Word("baz"), Word("qux"))))
+        Scaladoc(Seq(Paragraph(Tag(TagType.UseCase, label = label) +: rest)))
+      }
+    )
+  }
+
   test("parse tag") {
     assertEquals(
       parseString(