Skip to content

Commit 2430188

Browse files
committed
Improve symbol order in completions provided by the presentation compiler
Extension methods that are not in the same file are placed after all Product methods and even after extension methods like "ensuring". This PR penalizes the following methods, so that they are no longer at the top of the suggestions: - scala.Product.* - scala.Equals.* - scala.Predef.ArrowAssoc.* - scala.Predef.Ensuring.* - scala.Predef.StringFormat.* - scala.Predef.nn - scala.Predef.runtimeChecked Resolves scalameta/metals#7642
1 parent 7cbadac commit 2430188

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,13 @@ class Completions(
766766
).flatMap(_.alternatives.map(_.symbol)).toSet
767767
)
768768

769+
private lazy val EqualsClass: ClassSymbol = requiredClass("scala.Equals")
770+
private lazy val ArrowAssocClass: ClassSymbol = requiredClass("scala.Predef.ArrowAssoc")
771+
private lazy val EnsuringClass: ClassSymbol = requiredClass("scala.Predef.Ensuring")
772+
private lazy val StringFormatClass: ClassSymbol = requiredClass("scala.Predef.StringFormat")
773+
private lazy val nnMethod: Symbol = defn.ScalaPredefModule.requiredMethod("nn")
774+
private lazy val runtimeCheckedMethod: Symbol = defn.ScalaPredefModule.requiredMethod("runtimeChecked")
775+
769776
private def isNotLocalForwardReference(sym: Symbol)(using Context): Boolean =
770777
!sym.isLocalToBlock ||
771778
!sym.srcPos.isAfter(completionPos.originalCursorPosition) ||
@@ -784,6 +791,17 @@ class Completions(
784791
(sym.isField && !isJavaClass && !isModuleOrClass) || sym.getter != NoSymbol
785792
catch case _ => false
786793

794+
def isInheritedFromScalaLibrary(sym: Symbol) =
795+
sym.owner == defn.AnyClass ||
796+
sym.owner == defn.ObjectClass ||
797+
sym.owner == defn.ProductClass ||
798+
sym.owner == EqualsClass ||
799+
sym.owner == ArrowAssocClass ||
800+
sym.owner == EnsuringClass ||
801+
sym.owner == StringFormatClass ||
802+
sym == nnMethod ||
803+
sym == runtimeCheckedMethod
804+
787805
def symbolRelevance(sym: Symbol): Int =
788806
var relevance = 0
789807
// symbols defined in this file are more relevant
@@ -801,7 +819,7 @@ class Completions(
801819
case _ =>
802820

803821
// symbols whose owner is a base class are less relevant
804-
if sym.owner == defn.AnyClass || sym.owner == defn.ObjectClass
822+
if isInheritedFromScalaLibrary(sym)
805823
then relevance |= IsInheritedBaseMethod
806824
// symbols not provided via an implicit are more relevant
807825
if sym.is(Implicit) ||
@@ -813,7 +831,7 @@ class Completions(
813831
// accessors of case class members are more relevant
814832
if !sym.is(CaseAccessor) then relevance |= IsNotCaseAccessor
815833
// public symbols are more relevant
816-
if !sym.isPublic then relevance |= IsNotCaseAccessor
834+
if !sym.isPublic then relevance |= IsNotPublic
817835
// synthetic symbols are less relevant (e.g. `copy` on case classes)
818836
if sym.is(Synthetic) && !sym.isAllOf(EnumCase) then
819837
relevance |= IsSynthetic

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,44 @@ class CompletionExtensionSuite extends BaseCompletionSuite:
437437
|""".stripMargin,
438438
assertSingleItem = false
439439
)
440+
441+
@Test def `extension-for-case-class` =
442+
check(
443+
"""|case class Bar():
444+
| def baz(): Unit = ???
445+
|
446+
|object Bar:
447+
| extension (f: Bar)
448+
| def qux: Unit = ???
449+
|
450+
|object Main:
451+
| val _ = Bar().@@
452+
|""".stripMargin,
453+
"""|baz(): Unit
454+
|copy(): Bar
455+
|qux: Unit
456+
|asInstanceOf[X0]: X0
457+
|canEqual(that: Any): Boolean
458+
|equals(x$0: Any): Boolean
459+
|getClass[X0 >: Bar](): Class[? <: X0]
460+
|hashCode(): Int
461+
|isInstanceOf[X0]: Boolean
462+
|productArity: Int
463+
|productElement(n: Int): Any
464+
|productElementName(n: Int): String
465+
|productElementNames: Iterator[String]
466+
|productIterator: Iterator[Any]
467+
|productPrefix: String
468+
|synchronized[X0](x$0: X0): X0
469+
|toString(): String
470+
|->[B](y: B): (Bar, B)
471+
|ensuring(cond: Boolean): Bar
472+
|ensuring(cond: Bar => Boolean): Bar
473+
|ensuring(cond: Boolean, msg: => Any): Bar
474+
|ensuring(cond: Bar => Boolean, msg: => Any): Bar
475+
|nn: `?1`.type
476+
|runtimeChecked: `?2`.type
477+
|formatted(fmtstr: String): String
478+
|→[B](y: B): (Bar, B)
479+
| """.stripMargin
480+
)

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,9 @@ class CompletionSuite extends BaseCompletionSuite:
109109
|tabulate[A](n: Int)(f: Int => A): List[A]
110110
|unapplySeq[A](x: List[A] @uncheckedVariance): UnapplySeqWrapper[A]
111111
|unfold[A, S](init: S)(f: S => Option[(A, S)]): List[A]
112-
|->[B](y: B): (List.type, B)
113-
|ensuring(cond: Boolean): List.type
114-
|ensuring(cond: List.type => Boolean): List.type
115-
|ensuring(cond: Boolean, msg: => Any): List.type
116-
|ensuring(cond: List.type => Boolean, msg: => Any): List.type
117112
|fromSpecific(from: Any)(it: IterableOnce[Nothing]): List[Nothing]
118113
|fromSpecific(it: IterableOnce[Nothing]): List[Nothing]
119-
|nn: List.type
120-
|runtimeChecked scala.collection.immutable
121114
|toFactory(from: Any): Factory[Nothing, List[Nothing]]
122-
|formatted(fmtstr: String): String
123-
|→[B](y: B): (List.type, B)
124115
|iterableFactory[A]: Factory[A, List[A]]
125116
|asInstanceOf[X0]: X0
126117
|equals(x$0: Any): Boolean
@@ -129,6 +120,15 @@ class CompletionSuite extends BaseCompletionSuite:
129120
|isInstanceOf[X0]: Boolean
130121
|synchronized[X0](x$0: X0): X0
131122
|toString(): String
123+
|->[B](y: B): (List.type, B)
124+
|ensuring(cond: Boolean): List.type
125+
|ensuring(cond: List.type => Boolean): List.type
126+
|ensuring(cond: Boolean, msg: => Any): List.type
127+
|ensuring(cond: List.type => Boolean, msg: => Any): List.type
128+
|nn: List.type
129+
|runtimeChecked scala.collection.immutable
130+
|formatted(fmtstr: String): String
131+
|→[B](y: B): (List.type, B)
132132
|""".stripMargin
133133
)
134134

0 commit comments

Comments
 (0)