diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala index 8e5f5b662de..016e688fbd9 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala @@ -963,10 +963,26 @@ class MetalsGlobal( } else { other.dealiased == sym.dealiased || other.companion == sym.dealiased || - semanticdbSymbol(other.dealiased) == semanticdbSymbol(sym.dealiased) + semanticdbSymbol(other.dealiased) == semanticdbSymbol(sym.dealiased) || + isScalaPackageObjectReexport(other) } } + /** + * Check if the symbol is a `scala.*` `val` re-export of `other` + * + * @param other + * @return + */ + private def isScalaPackageObjectReexport(other: Symbol): Boolean = + sym.tpe match { + case NullaryMethodType(resultType: SingleType) => + sym.isDefinedInPackage && sym.isStable && + sym.effectiveOwner.name.toTermName == termNames.scala_ && + resultType =:= other.tpe + case _ => false + } + def snippetCursor: String = sym.paramss match { case Nil => diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/completions/MatchCaseCompletions.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/completions/MatchCaseCompletions.scala index 967d063653e..8f06d24841c 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/completions/MatchCaseCompletions.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/completions/MatchCaseCompletions.scala @@ -10,7 +10,6 @@ import scala.meta.internal.jdk.CollectionConverters._ import scala.meta.internal.metals.PcQueryContext import scala.meta.internal.mtags.MtagsEnrichments._ import scala.meta.internal.pc.CompletionFuzzy -import scala.meta.internal.pc.Identifier import scala.meta.internal.pc.MetalsGlobal import org.eclipse.{lsp4j => l} @@ -83,6 +82,7 @@ trait MatchCaseCompletions { this: MetalsGlobal => override def contribute: List[Member] = { val selectorSym = parents.selector.typeSymbol + val autoImport = autoImportPosition(pos, text) // Special handle case when selector is a tuple or `FunctionN`. if (definitions.isTupleType(parents.selector)) { @@ -110,11 +110,7 @@ trait MatchCaseCompletions { this: MetalsGlobal => ) val result = ListBuffer.empty[(Symbol, TextEditMember)] val isVisited = mutable.Set.empty[Symbol] - def visit( - sym: Symbol, - name: String, - autoImports: List[l.TextEdit] - ): Unit = { + def visit(sym: Symbol): Unit = { val fsym = sym.dealiasedSingleType def recordVisit(s: Symbol): Unit = { if (s != NoSymbol && !isVisited(s)) { @@ -127,6 +123,16 @@ trait MatchCaseCompletions { this: MetalsGlobal => if (!isVisited(sym) && !isVisited(fsym)) { recordVisit(sym) recordVisit(fsym) + + val (name, autoImports) = autoImport match { + case Some(value) => + val (shortName, edits) = + ShortenedNames.synthesize(sym, pos, context, value) + (shortName, edits) + case None => + (sym.fullNameSyntax, Nil) + } + if (fuzzyMatches(name)) result += (( sym, @@ -150,7 +156,7 @@ trait MatchCaseCompletions { this: MetalsGlobal => !(selectorSym.isSealed && (selectorSym.isAbstract || selectorSym.isTrait)) ) - visit(selectorSym, Identifier(selectorSym.name), Nil) + visit(selectorSym) } // Step 1: walk through scope members. @@ -163,24 +169,16 @@ trait MatchCaseCompletions { this: MetalsGlobal => fsym.hasModuleFlag || fsym.isInstanceOf[TypeSymbol]) && parents.isSubClass(fsym, includeReverse = false) - if (isValid) visit(sym, Identifier(m.sym.name), Nil) + if (isValid) visit(sym) } // Step 2: walk through known direct subclasses of sealed types. // In `List(foo).map { cas@@} we want to provide also `case (exhaustive)` completion // which works like exhaustive match, so we need to collect only members from this step - val autoImport = autoImportPosition(pos, text) val sealedDescs = mutable.Set.empty[Symbol] selectorSym.foreachKnownDirectSubClass { sym => sealedDescs += sym.dealiased - autoImport match { - case Some(value) => - val (shortName, edits) = - ShortenedNames.synthesize(sym, pos, context, value) - visit(sym, shortName, edits) - case None => - visit(sym, sym.fullNameSyntax, Nil) - } + visit(sym) } val members = result.result() val edits = { diff --git a/tests/cross/src/test/scala/tests/pc/CompletionCaseSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionCaseSuite.scala index f5caef1f4b1..994352a9ab2 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionCaseSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionCaseSuite.scala @@ -165,8 +165,6 @@ class CompletionCaseSuite extends BaseCompletionSuite { |""".stripMargin ) - // TODO: `Left` has conflicting name in Scope, we should fix it so the result is the same as for scala 2 - // Issue: https://github.com/scalameta/metals/issues/4368 check( "sealed-conflict", """ @@ -860,4 +858,56 @@ class CompletionCaseSuite extends BaseCompletionSuite { "" ) + checkEdit( + "underscore-autoimport", + """ + |object Outer { + | class Cls + |} + |object A { + | val t: Outer.Cls = ??? + | t match { + | case@@ + | } + |}""".stripMargin, + """ + |import Outer.Cls + | + |object Outer { + | class Cls + |} + |object A { + | val t: Outer.Cls = ??? + | t match { + | case _: Cls => $0 + | } + |}""".stripMargin + ) + + checkEdit( + "case-class-autoimport", + """ + |object Outer { + | case class Cls(i: Int) + |} + |object A { + | val t: Outer.Cls = ??? + | t match { + | case@@ + | } + |}""".stripMargin, + """ + |import Outer.Cls + | + |object Outer { + | case class Cls(i: Int) + |} + |object A { + | val t: Outer.Cls = ??? + | t match { + | case Cls(i) => $0 + | } + |}""".stripMargin + ) + } diff --git a/tests/cross/src/test/scala/tests/pc/SignatureHelpSuite.scala b/tests/cross/src/test/scala/tests/pc/SignatureHelpSuite.scala index a50ff39d344..4b9657f2c6a 100644 --- a/tests/cross/src/test/scala/tests/pc/SignatureHelpSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/SignatureHelpSuite.scala @@ -440,14 +440,7 @@ class SignatureHelpSuite extends BaseSignatureHelpSuite { """|to(end: Int): scala.collection.immutable.Range.Inclusive | ^^^^^^^^ |to(end: Int, step: Int): scala.collection.immutable.Range.Inclusive - |""".stripMargin, - "2.11" -> """|^^^^^^ - |to(end: Int): immutable.Range.Inclusive - |to(end: Int, step: Int): immutable.Range.Inclusive - |to(end: T): NumericRange.Inclusive[T] - |to(end: T): Range.Partial[T,NumericRange[T]] - |to(end: T, step: T): NumericRange.Inclusive[T] - |""".stripMargin + |""".stripMargin ) )