diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala index e7ad78b466e..e82d14fd806 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala @@ -99,7 +99,7 @@ class CompletionProvider( d.label case o: TextEditMember => o.label.getOrElse(labelWithSig) - case _: ExtensionMethod => + case _: WorkspaceImplicitMember => s"$labelWithSig (implicit)" case o: WorkspaceMember => s"$ident - ${o.sym.owner.fullName}" @@ -154,19 +154,19 @@ class CompletionProvider( item.setAdditionalTextEdits(i.autoImports.asJava) case d: DependecyMember => item.setTextEdit(d.edit) - case e: ExtensionMethod => + case m: WorkspaceImplicitMember => val impPos = importPosition.getOrElse(AutoImportPosition(0, 0, false)) val suffix = if ( - clientSupportsSnippets && e.sym.paramss.headOption.exists( + clientSupportsSnippets && m.sym.paramss.headOption.exists( _.nonEmpty ) ) "($0)" else "" val (short, edits) = ShortenedNames.synthesize( TypeRef( - ThisType(e.sym.owner), - e.sym, + ThisType(m.sym.owner), + m.sym, Nil ), pos, @@ -175,7 +175,7 @@ class CompletionProvider( ) val edit: l.TextEdit = textEdit( short + suffix, - e.editRange.getOrElse(editRange) + editRange ) item.setTextEdit(edit) item.setAdditionalTextEdits(edits.asJava) @@ -422,7 +422,7 @@ class CompletionProvider( param.info, typeParams ) => - visit(new ExtensionMethod(sym)) + visit(new WorkspaceImplicitMember(sym)) case _ => false } } else false diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/completions/Completions.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/completions/Completions.scala index 2d1436963cb..d67dd77080b 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/completions/Completions.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/completions/Completions.scala @@ -41,7 +41,8 @@ trait Completions { this: MetalsGlobal => def editRange: Option[l.Range] = None } - class ExtensionMethod(sym: Symbol) extends WorkspaceMember(sym) + class WorkspaceImplicitMember(sym: Symbol) + extends ScopeMember(sym, sym.tpe, true, EmptyTree) class WorkspaceInterpolationMember( sym: Symbol, diff --git a/tests/cross/src/test/scala/tests/pc/CompletionExtensionMethodSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionExtensionMethodSuite.scala index 269053fc3eb..6a72cb5d978 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionExtensionMethodSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionExtensionMethodSuite.scala @@ -4,11 +4,8 @@ import tests.BaseCompletionSuite class CompletionExtensionMethodSuite extends BaseCompletionSuite { - override def ignoreScalaVersion: Option[IgnoreScalaVersion] = - Some(IgnoreScala2) - check( - "simple", + "simple".tag(IgnoreScala2), """|package example | |object enrichments: @@ -25,18 +22,23 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "simple-old-syntax", """|package example | - |object Test: - | implicit class TestOps(a: Int): + |object Test { + | implicit class TestOps(a: Int) { | def testOps(b: Int): String = ??? + | } + |} | - |def main = 100.test@@ + |object O{ + | def main = 100.test@@ + |} |""".stripMargin, """|testOps(b: Int): String (implicit) - |""".stripMargin + |""".stripMargin, + filter = _.contains("(implicit)") ) check( - "simple2", + "simple2".tag(IgnoreScala2), """|package example | |object enrichments: @@ -54,11 +56,15 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "simple2-old-syntax", """|package example | - |object enrichments: - | implicit class TestOps(a: Int): + |object enrichments { + | implicit class TestOps(a: Int) { | def testOps(b: Int): String = ??? + | } + |} | - |def main = 100.t@@ + |object O { + | def main = 100.t@@ + |} |""".stripMargin, """|testOps(b: Int): String (implicit) |""".stripMargin, @@ -66,7 +72,7 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { ) check( - "simple-empty", + "simple-empty".tag(IgnoreScala2), """|package example | |object enrichments: @@ -84,11 +90,15 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "simple-empty-old", """|package example | - |object enrichments: - | implicit class TestOps(a: Int): + |object enrichments { + | implicit class TestOps(a: Int) { | def testOps(b: Int): String = ??? + | } + |} | - |def main = 100.@@ + |object O { + | def main = 100.@@ + |} |""".stripMargin, """|testOps(b: Int): String (implicit) |""".stripMargin, @@ -96,7 +106,7 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { ) check( - "filter-by-type", + "filter-by-type".tag(IgnoreScala2), """|package example | |object enrichments: @@ -116,21 +126,26 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "filter-by-type-old", """|package example | - |object enrichments: - | implicit class A(num: Int): + |object enrichments { + | implicit class A(num: Int) { | def identity2: Int = num + 1 - | implicit class B(str: String): + | } + | implicit class B(str: String) { | def identity: String = str + | } + |} | - |def main = "foo".iden@@ + |object O { + | def main = "foo".iden@@ + |} |""".stripMargin, """|identity: String (implicit) - |""".stripMargin // identity2 won't be available - + |""".stripMargin, // identity2 won't be available + filter = _.contains("(implicit)") ) check( - "filter-by-type-subtype", + "filter-by-type-subtype".tag(IgnoreScala2), """|package example | |class A @@ -154,11 +169,15 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { |class A |class B extends A | - |object enrichments: - | implicit class Test(a: A): + |object enrichments { + | implicit class Test(a: A) { | def doSomething: A = a + | } + |} | - |def main = (new B).do@@ + |object O { + | def main = (new B).do@@ + |} |""".stripMargin, """|doSomething: A (implicit) |""".stripMargin, @@ -166,7 +185,7 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { ) checkEdit( - "simple-edit", + "simple-edit".tag(IgnoreScala2), """|package example | |object enrichments: @@ -191,26 +210,35 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "simple-edit-old", """|package example | - |object enrichments: - | implicit class A (num: Int): + |object enrichments { + | implicit class A (num: Int) { | def incr: Int = num + 1 + | } + |} | - |def main = 100.inc@@ + |object O { + | def main = 100.inc@@ + |} |""".stripMargin, """|package example | |import example.enrichments.A | - |object enrichments: - | implicit class A (num: Int): + |object enrichments { + | implicit class A (num: Int) { | def incr: Int = num + 1 + | } + |} | - |def main = 100.incr - |""".stripMargin + |object O { + | def main = 100.incr + |} + |""".stripMargin, + filter = _.contains("(implicit)") ) checkEdit( - "simple-edit-suffix", + "simple-edit-suffix".tag(IgnoreScala2), """|package example | |object enrichments: @@ -232,7 +260,7 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { ) checkEdit( - "name-conflict", + "name-conflict".tag(IgnoreScala2), """|package example | |import example.enrichments.* @@ -265,28 +293,38 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "simple-edit-suffix-old", """|package example | - |object enrichments: - | implicit class A (val num: Int): + |object enrichments { + | implicit class A (val num: Int) { | def plus(other: Int): Int = num + other + | } + |} | - |def main = 100.pl@@ + |object O { + | def main = 100.pl@@ + |} |""".stripMargin, """|package example | |import example.enrichments.A | - |object enrichments: - | implicit class A (val num: Int): + |object enrichments { + | implicit class A (val num: Int) { | def plus(other: Int): Int = num + other + | } + |} | - |def main = 100.plus($0) + |object O { + | def main = 100.plus($0) + |} |""".stripMargin ) // NOTE: In 3.1.3, package object name includes the whole path to file // eg. in 3.2.2 we get `A$package`, but in 3.1.3 `/some/path/to/file/A$package` check( - "directly-in-pkg1".tag(IgnoreScalaVersion.forLessThan("3.2.2")), + "directly-in-pkg1".tag( + IgnoreScalaVersion.forLessThan("3.2.2") + ), """| |package example: | extension (num: Int) @@ -305,19 +343,24 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { IgnoreScalaVersion.forLessThan("3.2.2") ), """| - |package examples: - | implicit class A(num: Int): + |package examples { + | implicit class A(num: Int) { | def incr: Int = num + 1 + | } + |} | - |package examples2: + |package examples2 { | def main = 100.inc@@ + |} |""".stripMargin, """|incr: Int (implicit) |""".stripMargin ) check( - "directly-in-pkg2".tag(IgnoreScalaVersion.forLessThan("3.2.2")), + "directly-in-pkg2".tag( + IgnoreScalaVersion.forLessThan("3.2.2") + ), """|package example: | object X: | def fooBar(num: Int) = num + 1 @@ -333,22 +376,30 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { check( "directly-in-pkg2-old" .tag( - IgnoreScalaVersion.forLessThan("3.2.2") + IgnoreScalaVersion.for3LessThan("3.2.2") ), - """|package examples: - | object X: + """|package examples { + | object X { | def fooBar(num: Int) = num + 1 + | } | implicit class A (num: Int) { def incr: Int = num + 1 } + |} | - |package examples2: - | def main = 100.inc@@ + |package examples2 { + | object O { + | def main = 100.inc@@ + | } + |} |""".stripMargin, """|incr: Int (implicit) - |""".stripMargin + |""".stripMargin, + filter = _.contains("(implicit)") ) checkEdit( - "directly-in-pkg3".tag(IgnoreScalaVersion.forLessThan("3.2.2")), + "directly-in-pkg3".tag( + IgnoreScalaVersion.forLessThan("3.2.2") + ), """|package example: | extension (num: Int) def incr: Int = num + 1 | @@ -367,21 +418,44 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { checkEdit( "directly-in-pkg3-old" .tag( - IgnoreScalaVersion.forLessThan("3.2.2") + IgnoreScalaVersion.for3LessThan("3.2.2") ), - """|package examples: + """|package examples { | implicit class A (num: Int) { def incr: Int = num + 1 } + |} | - |package examples2: - | def main = 100.inc@@ + |package examples2 { + | object O { + | def main = 100.inc@@ + | } + |} |""".stripMargin, """|import examples.A - |package examples: + |package examples { | implicit class A (num: Int) { def incr: Int = num + 1 } + |} | - |package examples2: - | def main = 100.incr - |""".stripMargin + |package examples2 { + | object O { + | def main = 100.incr + | } + |} + |""".stripMargin, + compat = Map( + "2" -> """|package examples { + | implicit class A (num: Int) { def incr: Int = num + 1 } + |} + | + |package examples2 { + | + | import examples.A + | object O { + | def main = 100.incr + | } + |} + |""".stripMargin + ), + filter = _.contains("(implicit)") ) check( @@ -405,18 +479,25 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { check( "nested-pkg-old" .tag( - IgnoreScalaVersion.forLessThan("3.2.2") + IgnoreScalaVersion.for3LessThan("3.2.2") ), - """|package aa: // some comment - | package cc: - | implicit class A (num: Int): + """|package aa { // some comment + | package cc { + | implicit class A (num: Int){ | def increment2 = num + 2 - | implicit class A (num: Int): + | } + | } + | implicit class A (num: Int) { | def increment = num + 1 + | } + |} | | - |package bb: - | def main: Unit = 123.incre@@ + |package bb { + | object O { + | def main: Unit = 123.incre@@ + | } + |} |""".stripMargin, """|increment: Int (implicit) |increment2: Int (implicit) @@ -427,41 +508,119 @@ class CompletionExtensionMethodSuite extends BaseCompletionSuite { "implicit-val-var".tag(IgnoreForScala3CompilerPC), """|package example | - |object Test: - | implicit class TestOps(val testArg: Int): + |object Test { + | implicit class TestOps(val testArg: Int) { | var testVar: Int = 42 | val testVal: Int = 42 | def testOps(b: Int): String = ??? + | } + |} | - |def main = 100.test@@ + |object O { + | def main = 100.test@@ + |} |""".stripMargin, """|testArg: Int (implicit) |testVal: Int (implicit) |testVar: Int (implicit) |testOps(b: Int): String (implicit) - |""".stripMargin + |""".stripMargin, + compat = Map( + "2" -> + """|testArg: Int (implicit) + |testOps(b: Int): String (implicit) + |testVal: Int (implicit) + |testVar: Int (implicit) + |""".stripMargin + ), + filter = _.contains("(implicit)") ) checkEdit( "implicit-val-edit".tag(IgnoreForScala3CompilerPC), """|package example | - |object Test: - | implicit class TestOps(a: Int): + |object Test { + | implicit class TestOps(a: Int) { | val testVal: Int = 42 + | } + |} | - |def main = 100.test@@ + |object O { + | def main = 100.test@@ + |} |""".stripMargin, """|package example | |import example.Test.TestOps | - |object Test: - | implicit class TestOps(a: Int): + |object Test { + | implicit class TestOps(a: Int) { | val testVal: Int = 42 + | } + |} | - |def main = 100.testVal - |""".stripMargin + |object O { + | def main = 100.testVal + |} + |""".stripMargin, + filter = _.contains("(implicit)") + ) + + check( + "complex-type-old", + """|package example + | + |object Test { + | implicit class TestOps(a: List[Int]) { + | def testOps(b: Int) = ??? + | } + |} + | + |object ActualTest { + | List(1).tes@@ + |} + |""".stripMargin, + "testOps(b: Int): Nothing (implicit)", + filter = _.contains("testOps") + ) + + check( + "complex-type-old2".tag(IgnoreScala3), + """|package example + | + |object Test { + | implicit class TestOps[T](a: List[T]) { + | def testOps(b: Int) = ??? + | } + |} + | + |object ActualTest { + | List(1).tes@@ + |} + |""".stripMargin, + "testOps(b: Int): Nothing (implicit)", + filter = _.contains("testOps") + ) + + check( + "complex-type-old3".tag(IgnoreScala3), + """|package example + | + |case class A[-T](t: T) + | + |object Test { + | implicit class TestOps[T](a: A[T]) { + | def testOps(b: Int) = ??? + | } + |} + | + |object ActualTest { + | A(1).tes@@ + |} + |""".stripMargin, + "testOps(b: Int): Nothing (implicit)", + filter = _.contains("testOps") ) } diff --git a/tests/cross/src/test/scala/tests/pc/CompletionSnippetSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionSnippetSuite.scala index 2d3c0ce0b17..87ee72600fa 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionSnippetSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionSnippetSuite.scala @@ -219,7 +219,7 @@ class CompletionSnippetSuite extends BaseCompletionSuite { "2.13" -> """|Iterable |Iterable[$0] {} - |IterableOnce[$0] {} + |IterableOnce[$0] |""".stripMargin, "3" -> """|Iterable[$0] {} diff --git a/tests/cross/src/test/scala/tests/pc/CompletionWorkspaceSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionWorkspaceSuite.scala index 7f2eaf6e4c3..e20e791fded 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionWorkspaceSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionWorkspaceSuite.scala @@ -1101,91 +1101,4 @@ class CompletionWorkspaceSuite extends BaseCompletionSuite { filter = _.contains("testOps") ) - checkEdit( - "implicit-class-edit", - """|package example - | - |object Test { - | implicit class TestOps(a: Int) { - | def testOps(b: Int) = ??? - | } - |} - | - |object ActualTest { - | 1.tes@@ - |} - |""".stripMargin, - """|package example - | - |import example.Test.TestOps - | - |object Test { - | implicit class TestOps(a: Int) { - | def testOps(b: Int) = ??? - | } - |} - | - |object ActualTest { - | 1.testOps($0) - |} - |""".stripMargin, - filter = _.contains("testOps") - ) - - check( - "implicit-class-edit-bound2", - """|package example - | - |object Test { - | implicit class TestOps(a: List[Int]) { - | def testOps(b: Int) = ??? - | } - |} - | - |object ActualTest { - | List(1).tes@@ - |} - |""".stripMargin, - "testOps(b: Int): Nothing (implicit)", - filter = _.contains("testOps") - ) - - check( - "implicit-class-edit-bound3".tag(IgnoreScala3), - """|package example - | - |object Test { - | implicit class TestOps[T](a: List[T]) { - | def testOps(b: Int) = ??? - | } - |} - | - |object ActualTest { - | List(1).tes@@ - |} - |""".stripMargin, - "testOps(b: Int): Nothing (implicit)", - filter = _.contains("testOps") - ) - - check( - "implicit-class-edit-bound4".tag(IgnoreScala3), - """|package example - | - |case class A[-T](t: T) - | - |object Test { - | implicit class TestOps[T](a: A[T]) { - | def testOps(b: Int) = ??? - | } - |} - | - |object ActualTest { - | A(1).tes@@ - |} - |""".stripMargin, - "testOps(b: Int): Nothing (implicit)", - filter = _.contains("testOps") - ) - }