Repository: scalameta/scalameta (scala)

Issue:
[4.9.4+] semanticdb-scalac fails compilation 
https://github.com/scalameta/scalameta/pull/3700 introduced a regression when compiling

```scala
trait AmbiguousMend {
  def x
}
```

## 🔴  KO `4.9.3+44-9061b514-SNAPSHOT` and later

Reproduced on 2.12.{17,18,19} & 2.13.{12,13,14} (didn't try others)

```
[error] java.lang.RuntimeException: ambiguous mend AmbiguousMend.scala@29..29  AmbiguousMend.scala@28..29 x
[error] 	at scala.sys.package$.error(package.scala:27)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.indexName(TextDocumentOps.scala:86)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.apply(TextDocumentOps.scala:170)
[error] 	at scala.meta.transversers.Traverser.applyRest(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.apply(TextDocumentOps.scala:175)
[error] 	at scala.meta.transversers.Traverser.$anonfun$apply$1(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.$anonfun$apply$1$adapted(Traverser.scala:4)
[error] 	at scala.collection.immutable.List.foreach(List.scala:334)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.applyRest(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.apply(TextDocumentOps.scala:175)
[error] 	at scala.meta.transversers.Traverser.applyDefn(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.apply(TextDocumentOps.scala:175)
[error] 	at scala.meta.transversers.Traverser.$anonfun$apply$1(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.$anonfun$apply$1$adapted(Traverser.scala:4)
[error] 	at scala.collection.immutable.List.foreach(List.scala:334)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.applyRest(Traverser.scala:4)
[error] 	at scala.meta.transversers.Traverser.apply(Traverser.scala:4)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument$traverser$1$.apply(TextDocumentOps.scala:175)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument.toTextDocument(TextDocumentOps.scala:179)
[error] 	at scala.meta.internal.semanticdb.scalac.TextDocumentOps$XtensionCompilationUnitDocument.toTextDocument(TextDocumentOps.scala:42
[error] 	at scala.meta.internal.semanticdb.scalac.SemanticdbPipeline$SemanticdbTyperComponent$ComputeSemanticdbPhase.saveSemanticdbForCompilationUnit(SemanticdbPipeline.scala:58)
[error] 	at scala.meta.internal.semanticdb.scalac.SemanticdbPipeline$SemanticdbTyperComponent$ComputeSemanticdbPhase.apply(SemanticdbPipeline.scala:62)
[error] 	at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:481)
[error] 	at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:428)
[error] 	at scala.meta.internal.semanticdb.scalac.SemanticdbPipeline$SemanticdbTyperComponent$ComputeSemanticdbPhase.run(SemanticdbPipeline.scala:70)
[error] 	at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1549)
[error] 	at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1533)
[error] 	at scala.tools.nsc.Global$Run.compileSources(Global.scala:1525)
[error] 	at scala.tools.nsc.Global$Run.compileFiles(Global.scala:1638)
[error] 	at scala.tools.xsbt.CachedCompiler0.run(CompilerBridge.scala:176)
[error] 	at scala.tools.xsbt.CachedCompiler0.run(CompilerBridge.scala:139)
[error] 	at scala.tools.xsbt.CompilerBridge.run(CompilerBridge.scala:43)
```

## ✅ OK `4.9.3+43-12686f38-SNAPSHOT` and earlier

```
Summary:
Schema => SemanticDB v4
Uri => AmbiguousMend.scala
Text => empty
Language => Scala
Symbols => 2 entries
Occurrences => 2 entries
Diagnostics => 1 entries

Symbols:
_empty_/AmbiguousMend# => trait AmbiguousMend extends AnyRef { +1 decls }
_empty_/AmbiguousMend#x(). => abstract method x: Unit

Occurrences:
[0:6..0:19) <= _empty_/AmbiguousMend#
[1:6..1:7) <= _empty_/AmbiguousMend#x().

Diagnostics:
[1:7..1:7) [warning] procedure syntax is deprecated: instead, add `: Unit` to explicitly declare `x`'s return type [quickfixable]
```

Pull request description:
For instance, we might substitute a `Type.Name("Unit")` when the type is missing in a method declaration, but its input position is empty as it isn't actually present in the itput, which might lead to errors due to hash collisions with a parameterless-method name.

Prior to v4.9.4, it "worked" since the position of the empty name was actually around the newline token rather than the preceding method-name token.

Fixes #3738.

Patch:
diff --git a/semanticdb/scalac/library/src/main/scala/scala/meta/internal/semanticdb/scalac/TextDocumentOps.scala b/semanticdb/scalac/library/src/main/scala/scala/meta/internal/semanticdb/scalac/TextDocumentOps.scala
index c06c379f30..0040589551 100644
--- a/semanticdb/scalac/library/src/main/scala/scala/meta/internal/semanticdb/scalac/TextDocumentOps.scala
+++ b/semanticdb/scalac/library/src/main/scala/scala/meta/internal/semanticdb/scalac/TextDocumentOps.scala
@@ -73,8 +73,10 @@ trait TextDocumentOps {
       locally {
         object traverser extends m.Traverser {
           private def indexName(mname: m.Name): Unit = {
+            val mpos = mname.pos
+            if (mpos.isEmpty) return // for instance, missing type in method declaration
             todo += mname
-            val range = mname.tokens.findNot(_.is[m.Token.LeftParen]).getOrElse(mname.pos)
+            val range = mname.tokens.findNot(_.is[m.Token.LeftParen]).getOrElse(mpos)
             mstarts.put(range.start, mname).foreach(errorAmbiguous("mStart", mname, _))
             mends.put(range.end, mname).foreach(errorAmbiguous("mEnd", mname, _))
           }


Test patch:
diff --git a/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/SemanticdbSuite.scala b/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/SemanticdbSuite.scala
index b9ed81ea6e..4444ecdc81 100644
--- a/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/SemanticdbSuite.scala
+++ b/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/SemanticdbSuite.scala
@@ -123,14 +123,21 @@ abstract class SemanticdbSuite extends FunSuite {
     unit.toTextDocument
   }
 
-  private def computeDatabaseSectionFromSnippet(code: String, sectionName: String): String = {
+  protected def computePayloadFromSnippet(code: String): String = {
     val document = computeDatabaseFromSnippet(code)
     val format = scala.meta.metap.Format.Detailed
-    val payload = s.Print.document(format, document).split(EOL)
-    val section = payload.dropWhile(_ != sectionName + ":").drop(1).takeWhile(_ != "")
-    section.mkString(EOL)
+    s.Print.document(format, document)
   }
 
+  protected def computeSectionFromPayload(payload: String, sectionName: String): String = {
+    val sectionLine = sectionName + ":"
+    payload.linesIterator.dropWhile(_ != sectionLine).drop(1).takeWhile(_ != "")
+      .mkString("", EOL, EOL)
+  }
+
+  protected def computeDatabaseSectionFromSnippet(code: String, sectionName: String): String =
+    computeSectionFromPayload(computePayloadFromSnippet(code), sectionName)
+
   def checkSection(code: String, expected: String, section: String)(implicit
       loc: munit.Location
   ): Unit = checkSection(code, code, expected, section)
diff --git a/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/TargetedSuite.scala b/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/TargetedSuite.scala
index 7433c00289..e81a51c0b2 100644
--- a/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/TargetedSuite.scala
+++ b/tests/jvm/src/test/scala/scala/meta/tests/semanticdb/TargetedSuite.scala
@@ -237,4 +237,35 @@ class TargetedSuite extends SemanticdbSuite {
       assertEquals(foo2, "n/ForCompWithFilter.foo.")
     }
   )
+
+  locally { // #3738
+    val code = """|trait AmbiguousMend {
+                  |  def x
+                  |}
+                  |""".stripMargin
+    test(code) {
+      assertEquals(
+        computePayloadFromSnippet(code).linesIterator.drop(3).filter(!_.startsWith("Uri => "))
+          .mkString("", "\n", "\n"),
+        """|Summary:
+           |Schema => SemanticDB v4
+           |Text => non-empty
+           |Language => Scala
+           |Symbols => 2 entries
+           |Occurrences => 2 entries
+           |
+           |Symbols:
+           |_empty_/AmbiguousMend# => trait AmbiguousMend extends AnyRef { +1 decls }
+           |  AnyRef => scala/AnyRef#
+           |_empty_/AmbiguousMend#x(). => abstract method x: Unit
+           |  Unit => scala/Unit#
+           |
+           |Occurrences:
+           |[0:6..0:19): AmbiguousMend <= _empty_/AmbiguousMend#
+           |[1:6..1:7): x <= _empty_/AmbiguousMend#x().
+           |""".stripMargin
+      )
+    }
+  }
+
 }