From 8ef313912dcdc626132b60f42240d1266a3ba2ac Mon Sep 17 00:00:00 2001 From: Jakub Ciesluk <323892@uwr.edu.pl> Date: Fri, 3 Nov 2023 11:52:40 +0100 Subject: [PATCH] review fixes --- .../decorations/SyntheticHoverProvider.scala | 25 ++------ .../internal/metals/MetalsLspService.scala | 5 +- .../internal/metals/UserConfiguration.scala | 7 +++ .../scala/meta/pc/PresentationCompiler.java | 6 +- .../java/scala/meta/pc/SyntheticOptions.java | 12 ---- .../scala/meta/internal/pc/MetalsGlobal.scala | 16 +++++ .../pc/PcSyntheticDecorationsProvider.scala | 11 +++- .../internal/pc/completions/Completions.scala | 14 +---- .../internal/mtags/MtagsEnrichments.scala | 17 +++++- .../scala/meta/internal/pc/PcCollector.scala | 18 ------ .../pc/PcSyntheticDecorationProvider.scala | 31 +++++----- .../pc/completions/NamedArgCompletions.scala | 16 +---- .../tests/pc/SyntheticDecorationsSuite.scala | 35 ++++++++++- .../SemanticTokensScala3ExpectSuite.scala | 37 ++--------- ...yntheticDecorationsScala3ExpectSuite.scala | 35 ++--------- .../scala/tests/BaseWorksheetLspSuite.scala | 18 +++--- .../main/scala/tests/TestScala3Compiler.scala | 49 +++++++++++++++ .../src/main/scala/tests/TestingClient.scala | 16 ++--- .../decorations3/example/GivenAlias.scala | 2 +- .../SyntheticDecorationsLspSuite.scala | 61 ++++++++++++------- .../tests/worksheets/WorksheetLspSuite.scala | 4 +- 21 files changed, 228 insertions(+), 207 deletions(-) delete mode 100644 mtags-interfaces/src/main/java/scala/meta/pc/SyntheticOptions.java create mode 100644 tests/unit/src/main/scala/tests/TestScala3Compiler.scala diff --git a/metals/src/main/scala/scala/meta/internal/decorations/SyntheticHoverProvider.scala b/metals/src/main/scala/scala/meta/internal/decorations/SyntheticHoverProvider.scala index 5f78be977be..03354087fe6 100644 --- a/metals/src/main/scala/scala/meta/internal/decorations/SyntheticHoverProvider.scala +++ b/metals/src/main/scala/scala/meta/internal/decorations/SyntheticHoverProvider.scala @@ -1,7 +1,6 @@ package scala.meta.internal.decorations import java.nio.charset.Charset -import java.util.concurrent.atomic.AtomicReference import scala.util.Try @@ -35,22 +34,15 @@ final class SyntheticHoverProvider( userConfig: () => UserConfiguration, trees: Trees, ) { - private object Document { - /* We update it with each compilation in order not read the same file on - * each change. When typing documents stay the same most of the time. - */ - private val document = new AtomicReference[TextDocument] - def currentDocument: Option[TextDocument] = Option(document.get()) - - def set(doc: TextDocument): Unit = document.set(doc) - } + @volatile private var document: Option[TextDocument] = + Option.empty[TextDocument] def addSyntheticsHover( params: HoverExtParams, pcHover: Option[l.Hover], ): Option[l.Hover] = - if (areSyntheticsEnabled) { + if (userConfig().areSyntheticsEnabled()) { val path = params.textDocument.getUri().toAbsolutePath val position = params.getPosition val line = position.getLine() @@ -107,13 +99,6 @@ final class SyntheticHoverProvider( pcHover } - private def areSyntheticsEnabled: Boolean = { - val showInferredType = !userConfig().showInferredType.contains( - "false" - ) && userConfig().showInferredType.nonEmpty - userConfig().showImplicitArguments || showInferredType || userConfig().showImplicitConversionsAndClasses - } - private def createHoverAtPoint( syntheticsAtLine: Seq[(l.Range, String)], pcHover: Option[l.Hover], @@ -196,7 +181,7 @@ final class SyntheticHoverProvider( } private def currentDocument(path: AbsolutePath): Option[TextDocument] = { - Document.currentDocument match { + document match { case Some(doc) if workspace.resolve(doc.uri) == path => Some(doc) case _ => val textDocument = semanticdbs @@ -214,7 +199,7 @@ final class SyntheticHoverProvider( doc <- textDocument source <- fingerprints.loadLastValid(path, doc.md5, charset) docWithText = doc.withText(source) - _ = Document.set(docWithText) + _ = document = Some(docWithText) } yield docWithText } diff --git a/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala b/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala index 9c92dc6a88f..f503fe9c506 100644 --- a/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala +++ b/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala @@ -1111,10 +1111,7 @@ class MetalsLspService( CancelTokens.future { token => val shouldShow = force || - userConfig.showInferredType.contains("true") || - userConfig.showInferredType.contains("minimal") || - userConfig.showImplicitArguments || - userConfig.showImplicitConversionsAndClasses + userConfig.areSyntheticsEnabled() if (shouldShow) { compilers.syntheticDecorations(path, token).map { decorations => val params = new PublishDecorationsParams( diff --git a/metals/src/main/scala/scala/meta/internal/metals/UserConfiguration.scala b/metals/src/main/scala/scala/meta/internal/metals/UserConfiguration.scala index 8491233c0bb..4361ec15ea4 100644 --- a/metals/src/main/scala/scala/meta/internal/metals/UserConfiguration.scala +++ b/metals/src/main/scala/scala/meta/internal/metals/UserConfiguration.scala @@ -61,6 +61,13 @@ case class UserConfiguration( bloopVersion.getOrElse(BuildInfo.bloopVersion) def usedJavaBinary(): Option[AbsolutePath] = JavaBinary.path(javaHome) + + def areSyntheticsEnabled(): Boolean = { + val showInferredType = !this.showInferredType.contains( + "false" + ) && this.showInferredType.nonEmpty + showImplicitArguments || showInferredType || showImplicitConversionsAndClasses + } } object UserConfiguration { diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java b/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java index 69cf4d8eeaf..af82134fa32 100644 --- a/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java +++ b/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java @@ -165,9 +165,11 @@ public abstract CompletableFuture> convertToNamedArguments(Offset public abstract CompletableFuture> didChange(VirtualFileParams params); /** - * + * Returns decorations for missing type adnotations, inferred type parameters, implicit parameters and conversions. */ - public abstract CompletableFuture> syntheticDecorations(SyntheticDecorationsParams params); + public CompletableFuture> syntheticDecorations(SyntheticDecorationsParams params) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } /** * File was closed. diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/SyntheticOptions.java b/mtags-interfaces/src/main/java/scala/meta/pc/SyntheticOptions.java deleted file mode 100644 index 783425bea24..00000000000 --- a/mtags-interfaces/src/main/java/scala/meta/pc/SyntheticOptions.java +++ /dev/null @@ -1,12 +0,0 @@ -package scala.meta.pc; - -import java.util.List; -import org.eclipse.lsp4j.Range; - - -public interface SyntheticOptions { - boolean inferredType(); - List missingTypes(); - boolean implicitParams(); - boolean implicitConversions(); -} \ No newline at end of file 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 1599f86b967..9b56037544c 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 @@ -1038,6 +1038,22 @@ class MetalsGlobal( syntheticName && wrongSpan } + private val infixNames = + Set(nme.apply, nme.unapply, nme.unapplySeq) + + def isInfix(tree: Tree, text: String): Boolean = + tree match { + case Select(New(_), _) => false + case Select(_, name: TermName) if infixNames(name) => false + case Select(This(_), _) => false + // is a select statement without a dot `qual.name` + case Select(qual, _) => { + val pos = qual.pos.end + pos < text.length() && text(pos) != '.' + } + case _ => false + } + // Extractor for both term and type applications like `foo(1)` and foo[T]` object TreeApply { def unapply(tree: Tree): Option[(Tree, List[Tree])] = diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/PcSyntheticDecorationsProvider.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/PcSyntheticDecorationsProvider.scala index bbff3bb0e63..cc33f8d696c 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/PcSyntheticDecorationsProvider.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/PcSyntheticDecorationsProvider.scala @@ -15,6 +15,8 @@ final class PcSyntheticDecorationsProvider( cursor = None ) lazy val text = unit.source.content + lazy val textStr = text.mkString + typeCheck(unit) def tpdTree = unit.lastBody @@ -104,7 +106,8 @@ final class PcSyntheticDecorationsProvider( object ImplicitParameters { def unapply(tree: Tree): Option[(List[String], Position, Boolean)] = tree match { - case Apply(_, args) if args.exists(isSyntheticArg) => + case Apply(_, args) + if args.exists(isSyntheticArg) && !tree.pos.isOffset => val (implicitArgs, providedArgs) = args.partition(isSyntheticArg) val allImplicit = providedArgs.isEmpty val pos = providedArgs.lastOption.fold(tree.pos)(_.pos) @@ -133,7 +136,11 @@ final class PcSyntheticDecorationsProvider( None case TypeApply(fun, args) if args.exists(_.pos.isOffset) && tree.pos.isRange => - val pos = fun.pos + val pos = fun match { + case sel: Select if isInfix(sel, textStr) => + sel.namePosition + case _ => fun.pos + } Some(args.map(_.tpe.widen.finalResultType), pos) case _ => None } 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 d0dc6f13745..4cee713c315 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 @@ -455,18 +455,6 @@ trait Completions { this: MetalsGlobal => ident: Ident, apply: Apply ): CompletionPosition = { - def isInfix(apply: Apply, text: String) = - apply.fun match { - case Select(New(_), _) => false - case Select(_, name) if name.decoded == "apply" => false - case Select(This(_), _) => false - // is a select statement without a dot `qual.name` - case Select(qual, _) => { - val pos = qual.pos.end - pos < text.length() && text(pos) != '.' - } - case _ => false - } if (hasLeadingBrace(ident, text)) { if (isCasePrefix(ident.name)) { val moveToNewLine = ident.pos.line == apply.pos.line @@ -485,7 +473,7 @@ trait Completions { this: MetalsGlobal => NoneCompletion } } else { - if (!isInfix(apply, text)) { + if (!isInfix(apply.fun, text)) { ArgCompletion(ident, apply, pos, text, completions) } else NoneCompletion } diff --git a/mtags/src/main/scala-3/scala/meta/internal/mtags/MtagsEnrichments.scala b/mtags/src/main/scala-3/scala/meta/internal/mtags/MtagsEnrichments.scala index dfe62ae3022..aef68f7763f 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/mtags/MtagsEnrichments.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/mtags/MtagsEnrichments.scala @@ -14,6 +14,7 @@ import scala.meta.pc.SymbolSearch import dotty.tools.dotc.ast.tpd.* import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Denotations.* +import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.NameOps.* import dotty.tools.dotc.core.Names.* @@ -256,6 +257,8 @@ object MtagsEnrichments extends ScalametaCommonEnrichments: end symbolDocumentation end extension + private val infixNames = + Set(nme.apply, nme.unapply, nme.unapplySeq) extension (tree: Tree) def qual: Tree = tree match @@ -271,6 +274,19 @@ object MtagsEnrichments extends ScalametaCommonEnrichments: val denot = sym.denot.asSeenFrom(pre.tpe.widenTermRefExpr) (denot.info, sym.withUpdatedTpe(denot.info)) catch case NonFatal(e) => (sym.info, sym) + + def isInfix(using ctx: Context) = + tree match + case Select(New(_), _) => false + case Select(_, name: TermName) if infixNames(name) => false + case Select(This(_), _) => false + // is a select statement without a dot `qual.name` + case sel @ Select(qual, _) if !sel.symbol.is(Flags.Synthetic) => + val source = tree.source + !(qual.span.end until sel.nameSpan.start) + .map(source.apply) + .contains('.') + case _ => false end extension extension (imp: Import) @@ -287,7 +303,6 @@ object MtagsEnrichments extends ScalametaCommonEnrichments: case _ => false val wrongSpan = sel.qualifier.span.contains(sel.nameSpan) syntheticName && wrongSpan - extension (denot: Denotation) def allSymbols: List[Symbol] = denot match diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala index 70f7e0c211c..9db5a9cc36f 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala @@ -447,24 +447,6 @@ abstract class PcCollector[T]( ) else occurences case _ => occurences - /** - * for synthetic decorations in: - * given Conversion[Int, String] = _.toString - * val x: String = <<>>123 - */ - case sel: Select - if sel.span.isZeroExtent && sel.symbol.is(Flags.ExtensionMethod) => - parent match - case Some(a: Apply) => - val span = a.span.withStart(a.span.point) - val amendedSelect = sel.withSpan(span) - if filter(amendedSelect) then - occurences + collect( - amendedSelect, - pos.withSpan(span), - ) - else occurences - case _ => occurences /* all definitions: * def <> = ??? * class <> = ??? diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcSyntheticDecorationProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcSyntheticDecorationProvider.scala index 6484fcce061..112422db5b1 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcSyntheticDecorationProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcSyntheticDecorationProvider.scala @@ -155,29 +155,28 @@ object ImplicitConversion: def unapply(tree: Tree)(using Context) = tree match case Apply(fun: Ident, args) if isSynthetic(fun) => - val lastArgPos = - args.lastOption.map(_.sourcePos).getOrElse(fun.sourcePos) - Some( - fun.symbol.decodedName, - lastArgPos.withStart(fun.sourcePos.start), - ) + implicitConversion(fun, args) case Apply(Select(fun, name), args) if name == nme.apply && isSynthetic(fun) => - val lastArgPos = - args.lastOption.map(_.sourcePos).getOrElse(fun.sourcePos) - Some( - fun.symbol.decodedName, - lastArgPos.withStart(fun.sourcePos.start), - ) + implicitConversion(fun, args) case _ => None private def isSynthetic(tree: Tree)(using Context) = tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit) + + private def implicitConversion(fun: Tree, args: List[Tree])(using Context) = + val lastArgPos = + args.lastOption.map(_.sourcePos).getOrElse(fun.sourcePos) + Some( + fun.symbol.decodedName, + lastArgPos.withStart(fun.sourcePos.start), + ) end ImplicitConversion object ImplicitParameters: def unapply(tree: Tree)(using Context) = tree match - case Apply(fun, args) if args.exists(isSyntheticArg) => + case Apply(fun, args) + if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent => val (implicitArgs, providedArgs) = args.partition(isSyntheticArg) val allImplicit = providedArgs.isEmpty val pos = implicitArgs.head.sourcePos @@ -204,8 +203,12 @@ object TypeParameters: tree match case TypeApply(sel: Select, _) if sel.isForComprehensionMethod => None case TypeApply(fun, args) if inferredTypeArgs(args) => + val pos = fun match + case sel: Select if sel.isInfix => + sel.sourcePos.withEnd(sel.nameSpan.end) + case _ => fun.sourcePos val tpes = args.map(_.tpe.stripTypeVar.widen.finalResultType) - Some((tpes, tree.endPos, fun)) + Some((tpes, pos.endPos, fun)) case _ => None private def inferredTypeArgs(args: List[Tree]): Boolean = args.forall { diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala index a18e7c3ffa1..96a33f9bf4d 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala @@ -38,7 +38,7 @@ object NamedArgCompletions: )(using ctx: Context): List[CompletionValue] = path match case (ident: Ident) :: ValDef(_, _, _) :: Block(_, app: Apply) :: _ - if !isInfix(pos, app) => + if !app.fun.isInfix => contribute( Some(ident), app, @@ -58,7 +58,7 @@ object NamedArgCompletions: val contribution = for app <- getApplyForContextFunctionParam(rest) - if !isInfix(pos, app) + if !app.fun.isInfix yield contribute( Some(ident), app, @@ -71,18 +71,6 @@ object NamedArgCompletions: end match end contribute - private def isInfix(pos: SourcePosition, apply: Apply)(using ctx: Context) = - apply.fun match - case Select(New(_), _) => false - case Select(_, name) if name.decoded == "apply" => false - case Select(This(_), _) => false - // is a select statement without a dot `qual.name` - case sel @ Select(qual, _) if !sel.symbol.is(Flags.Synthetic) => - !(qual.span.end until sel.nameSpan.start) - .map(pos.source.apply) - .contains('.') - case _ => false - private def contribute( ident: Option[Ident], apply: Apply, diff --git a/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala b/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala index b259a252281..ca80346e69a 100644 --- a/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala @@ -116,9 +116,8 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite { kind = Some(DecorationKind.ImplicitConversion), ) - // TODO: Examinate implicit conversion here and unignore check( - "wrong-given-conversion".ignore, + "given-conversion2".tag(IgnoreScala2), """|trait Xg: | def doX: Int |trait Yg: @@ -126,7 +125,13 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite { |given (using Xg): Yg with | def doY = "7" |""".stripMargin, - "", + """|trait Xg: + | def doX: Int + |trait Yg: + | def doY: String + |given (using Xg): Yg with + | def doY: String = "7" + |""".stripMargin, ) check( @@ -153,6 +158,18 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite { |""".stripMargin, ) + check( + "list2", + """|object O { + | def m = 1 :: List(1) + |} + |""".stripMargin, + """|object O { + | def m: List[Int] = 1 ::[Int] List[Int](1) + |} + |""".stripMargin, + ) + check( "two-param", """|object Main { @@ -504,4 +521,16 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite { |""".stripMargin, ) + check( + "case-class1", + """|object O { + |case class A(x: Int, g: Int)(implicit y: String) + |} + |""".stripMargin, + """|object O { + |case class A(x: Int, g: Int)(implicit y: String) + |} + |""".stripMargin, + ) + } diff --git a/tests/slow/src/test/scala/tests/feature/SemanticTokensScala3ExpectSuite.scala b/tests/slow/src/test/scala/tests/feature/SemanticTokensScala3ExpectSuite.scala index 8bd6f4fb513..bcfd4a69157 100644 --- a/tests/slow/src/test/scala/tests/feature/SemanticTokensScala3ExpectSuite.scala +++ b/tests/slow/src/test/scala/tests/feature/SemanticTokensScala3ExpectSuite.scala @@ -1,55 +1,26 @@ package tests.feature -import scala.meta.internal.io.PathIO -import scala.meta.internal.metals.Buffers -import scala.meta.internal.metals.ClientConfiguration import scala.meta.internal.metals.CompilerVirtualFileParams -import scala.meta.internal.metals.Embedded import scala.meta.internal.metals.EmptyCancelToken import scala.meta.internal.metals.MetalsEnrichments._ -import scala.meta.internal.metals.MtagsBinaries -import scala.meta.internal.metals.ProgressTicks import scala.meta.internal.metals.SemanticTokensProvider -import scala.meta.internal.metals.StatusBar import scala.meta.internal.metals.{BuildInfo => V} import tests.DirectoryExpectSuite import tests.ExpectTestCase -import tests.FakeTime import tests.InputProperties -import tests.TestMtagsResolver +import tests.TestScala3Compiler import tests.TestSemanticTokens -import tests.TestingClient class SemanticTokensScala3ExpectSuite( ) extends DirectoryExpectSuite("semanticTokens3") { override lazy val input: InputProperties = InputProperties.scala3() - private val compiler = { - val resolver = new TestMtagsResolver() - resolver.resolve(V.scala3) match { - - case Some(mtags: MtagsBinaries.Artifacts) => - val time = new FakeTime - val client = new TestingClient(PathIO.workingDirectory, Buffers()) - val status = new StatusBar( - client, - time, - ProgressTicks.dots, - ClientConfiguration.default, - )(munitExecutionContext) - val embedded = new Embedded(status) - embedded - .presentationCompiler(mtags, mtags.jars) - .newInstance( - "tokens", - input.classpath.entries.map(_.toNIO).asJava, - Nil.asJava, - ) + private val compiler = + TestScala3Compiler.compiler("tokens", input)(munitExecutionContext) match { + case Some(pc) => pc case _ => fail(s"Could not load ${V.scala3} presentation compiler") } - } - override def testCases(): List[ExpectTestCase] = { input.scalaFiles.map { file => ExpectTestCase( diff --git a/tests/slow/src/test/scala/tests/feature/SyntheticDecorationsScala3ExpectSuite.scala b/tests/slow/src/test/scala/tests/feature/SyntheticDecorationsScala3ExpectSuite.scala index 62625ab1d3e..0d7a6f3e540 100644 --- a/tests/slow/src/test/scala/tests/feature/SyntheticDecorationsScala3ExpectSuite.scala +++ b/tests/slow/src/test/scala/tests/feature/SyntheticDecorationsScala3ExpectSuite.scala @@ -1,21 +1,11 @@ package tests.feature -import scala.meta.internal.io.PathIO -import scala.meta.internal.metals.Buffers -import scala.meta.internal.metals.ClientConfiguration -import scala.meta.internal.metals.Embedded -import scala.meta.internal.metals.MetalsEnrichments._ -import scala.meta.internal.metals.MtagsBinaries -import scala.meta.internal.metals.ProgressTicks -import scala.meta.internal.metals.StatusBar import scala.meta.internal.metals.{BuildInfo => V} import scala.meta.pc.PresentationCompiler import tests.BaseSyntheticDecorationsExpectSuite -import tests.FakeTime import tests.InputProperties -import tests.TestMtagsResolver -import tests.TestingClient +import tests.TestScala3Compiler class SyntheticDecorationsScala3ExpectSuite( ) extends BaseSyntheticDecorationsExpectSuite( @@ -23,25 +13,10 @@ class SyntheticDecorationsScala3ExpectSuite( InputProperties.scala3(), ) { override val compiler: PresentationCompiler = { - val resolver = new TestMtagsResolver() - resolver.resolve(V.scala3) match { - case Some(mtags: MtagsBinaries.Artifacts) => - val time = new FakeTime - val client = new TestingClient(PathIO.workingDirectory, Buffers()) - val status = new StatusBar( - client, - time, - ProgressTicks.dots, - ClientConfiguration.default, - )(munitExecutionContext) - val embedded = new Embedded(status) - embedded - .presentationCompiler(mtags, mtags.jars) - .newInstance( - "tokens", - input.classpath.entries.map(_.toNIO).asJava, - Nil.asJava, - ) + TestScala3Compiler.compiler("decorations", input)( + munitExecutionContext + ) match { + case Some(pc) => pc case _ => fail(s"Could not load ${V.scala3} presentation compiler") } diff --git a/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala b/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala index ce5167138cd..fc9083a471a 100644 --- a/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala +++ b/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala @@ -74,7 +74,7 @@ abstract class BaseWorksheetLspSuite( ) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, getExpected( """|identity(42) // : Int = 42 |val name = sourcecode.Name.generate.value // : String = "name" @@ -103,9 +103,9 @@ abstract class BaseWorksheetLspSuite( ) _ <- server.didOpen("a/Main.worksheet.sc") // check that ANSI colors were stripped - _ = assertNotContains(client.workspaceDecorations, "\u001b") + _ = assertNotContains(client.syntheticDecorations, "\u001b") _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|pprint.pprintln("Hello, world!") // "Hello, world!" |""".stripMargin, ) @@ -131,7 +131,7 @@ abstract class BaseWorksheetLspSuite( _ <- server.didOpen("a/Main.worksheet.sc") _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, getExpected( """|import java.nio.file.Files |val name = "Susan" // : String = "Susan" @@ -176,7 +176,7 @@ abstract class BaseWorksheetLspSuite( _ <- server.didOpen("a/src/main/scala/Main.worksheet.sc") _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, getExpected( """|import java.nio.file.Files |val name = "Susan" // : String = "Susan" @@ -199,7 +199,7 @@ abstract class BaseWorksheetLspSuite( ), ) _ = assertNoDiff( - client.workspaceDecorationHoverMessage, + client.syntheticDecorationHoverMessage, getExpected( """|import java.nio.file.Files |val name = "Susan" @@ -285,7 +285,7 @@ abstract class BaseWorksheetLspSuite( _.replace("42", "43") ) _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """| |println(43) // 43 |// Stream.from(10).last @@ -308,7 +308,7 @@ abstract class BaseWorksheetLspSuite( ) _ <- server.didOpen("a/src/main/scala/Main.worksheet.sc") _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """| |val x = 42 // : Int = 42 |throw new RuntimeException("boom") @@ -394,7 +394,7 @@ abstract class BaseWorksheetLspSuite( // completions work despite error _ = assertNoDiff(identity, "identity[A](x: A): A") // decorations do not appear for non ".worksheet.sc" files. - _ = assertNoDiff(client.workspaceDecorations, "") + _ = assertNoDiff(client.syntheticDecorations, "") } yield () } diff --git a/tests/unit/src/main/scala/tests/TestScala3Compiler.scala b/tests/unit/src/main/scala/tests/TestScala3Compiler.scala new file mode 100644 index 00000000000..69980bc636b --- /dev/null +++ b/tests/unit/src/main/scala/tests/TestScala3Compiler.scala @@ -0,0 +1,49 @@ +package tests + +import scala.concurrent.ExecutionContext + +import scala.meta.internal.io.PathIO +import scala.meta.internal.metals.Buffers +import scala.meta.internal.metals.ClientConfiguration +import scala.meta.internal.metals.Embedded +import scala.meta.internal.metals.MetalsEnrichments._ +import scala.meta.internal.metals.MtagsBinaries +import scala.meta.internal.metals.ProgressTicks +import scala.meta.internal.metals.StatusBar +import scala.meta.internal.metals.{BuildInfo => V} +import scala.meta.pc.PresentationCompiler + +import tests.FakeTime +import tests.InputProperties +import tests.TestMtagsResolver +import tests.TestingClient + +object TestScala3Compiler { + def compiler(name: String, input: InputProperties)(implicit + ec: ExecutionContext + ): Option[PresentationCompiler] = { + val resolver = new TestMtagsResolver() + resolver.resolve(V.scala3) match { + case Some(mtags: MtagsBinaries.Artifacts) => + val time = new FakeTime + val client = new TestingClient(PathIO.workingDirectory, Buffers()) + val status = new StatusBar( + client, + time, + ProgressTicks.dots, + ClientConfiguration.default, + )(ec) + val embedded = new Embedded(status) + val pc = embedded + .presentationCompiler(mtags, mtags.jars) + .newInstance( + name, + input.classpath.entries.map(_.toNIO).asJava, + Nil.asJava, + ) + Some(pc) + case _ => None + } + + } +} diff --git a/tests/unit/src/main/scala/tests/TestingClient.scala b/tests/unit/src/main/scala/tests/TestingClient.scala index 39d327299cb..34ea75f44aa 100644 --- a/tests/unit/src/main/scala/tests/TestingClient.scala +++ b/tests/unit/src/main/scala/tests/TestingClient.scala @@ -454,23 +454,23 @@ class TestingClient(workspace: AbsolutePath, val buffers: Buffers) ) } - def workspaceDecorations: String = { - workspaceDecorations(isHover = false) + def syntheticDecorations: String = { + syntheticDecorations(isHover = false) } def workspaceDecorations(filename: String): String = { - workspaceDecorations(isHover = false, Some(filename)) + syntheticDecorations(isHover = false, Some(filename)) } - def workspaceDecorationHoverMessage: String = - workspaceDecorations(isHover = true) + def syntheticDecorationHoverMessage: String = + syntheticDecorations(isHover = true) - def workspaceDecorationHoverMessage( + def syntheticDecorationHoverMessage( filename: String ): String = { - workspaceDecorations(isHover = true, Some(filename)) + syntheticDecorations(isHover = true, Some(filename)) } - private def workspaceDecorations( + private def syntheticDecorations( isHover: Boolean, filename: Option[String] = None, ): String = { diff --git a/tests/unit/src/test/resources/decorations3/example/GivenAlias.scala b/tests/unit/src/test/resources/decorations3/example/GivenAlias.scala index 884d728eb29..4e229ca6062 100644 --- a/tests/unit/src/test/resources/decorations3/example/GivenAlias.scala +++ b/tests/unit/src/test/resources/decorations3/example/GivenAlias.scala @@ -28,7 +28,7 @@ trait Zg[T]: given Xg with def doX/*: Int*/ = 7 -/*(x$1)*/given (using Xg): Yg with +given (using Xg): Yg with def doY/*: String*/ = "7" given [T]: Zg[T] with diff --git a/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala b/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala index ac3df1193ac..59488221d7b 100644 --- a/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala +++ b/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala @@ -64,7 +64,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( // foo[t]() to foo() - client.workspaceDecorations, + client.syntheticDecorations, """|import scala.concurrent.Future |case class Location(city: String) |object Main{ @@ -101,7 +101,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|import scala.concurrent.Future |case class Location(city: String) |object Main{ @@ -236,7 +236,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | def hello()(implicit name: String) = { | println(s"Hello $name!") @@ -258,7 +258,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { ) _ <- server.didOpen("a/src/main/scala/Main.scala") _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | def hello()(implicit name: String): Unit = { | println(s"Hello $name!") @@ -280,7 +280,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { ) _ <- server.didOpen("a/src/main/scala/Main.scala") _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | def hello()(implicit name: String) = { | println(s"Hello $name!") @@ -301,7 +301,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { |""".stripMargin ) _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | def hello()(implicit name: String) = { | println(s"Hello $name!") @@ -342,7 +342,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | augmentString(augmentString((augmentString("1" + "2")) | .stripSuffix(".")) @@ -389,7 +389,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didOpen("standalone/Main.scala") _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | val value: String = augmentString("asd.").stripSuffix(".") |} @@ -415,7 +415,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { } _ <- server.didSave("standalone/Main.scala")(identity) _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | augmentString("asd.").stripSuffix(".") | augmentString("asd.").stripSuffix(".") @@ -488,7 +488,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | val head: Double :: tail: List[Double] = List[Double](0.1, 0.2, 0.3) | val List[Int](l1: Int, l2: Int) = List[Int](12, 13) @@ -576,7 +576,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|import scala.concurrent.ExecutionContextExecutorService | |trait A @@ -628,7 +628,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object Main{ | val abc: Int = 123 |} @@ -639,7 +639,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { "\n" + text } _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """| |object Main{ | val abc: Int = 123 @@ -650,6 +650,15 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didChange("a/src/main/scala/Main.scala") { text => "}\n" + text } + _ = assertNoDiff( + client.syntheticDecorations, + """|} + | + |object Main{ + | val abc: Int = 123 + |} + |""".stripMargin, + ) } yield () } @@ -705,7 +714,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|import cats.Parallel |import cats.effect.ConcurrentEffect |import cats.effect.ContextShift @@ -750,7 +759,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didOpen("a/Main.worksheet.sc") _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|def method(implicit str: String) = str + str |implicit val name: String = "Susan".stripMargin // : String = "Susan" |val greeting = s"Hello $name" // : String = "Hello Susan" @@ -766,7 +775,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { |""".stripMargin ) _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|def method(implicit str: String): String = str + str |implicit val name: String = augmentString("Susan").stripMargin // : String = "Susan" |val greeting: String = s"Hello $name" // : String = "Hello Susan" @@ -786,6 +795,10 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { |/a/Main.scala |class Evidence | + |final case class DataType[T](number: Int, other: T) { + | def next(implicit evidence: Evidence): Int = number + 1 + |} + | |object Example extends App { | | implicit val evidence: Evidence = ??? @@ -795,8 +808,9 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { | number <- Option(5) | num2 <- opts(2) | _ = "abc ".stripMargin - | } yield 1 + | } yield DataType(number, "").next | + | Option(5).map(DataType(_, "").next) |} |""".stripMargin ) @@ -811,8 +825,12 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didOpen("a/Main.scala") _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|class Evidence + | + |final case class DataType[T](number: Int, other: T) { + | def next(implicit evidence: Evidence): Int = number + 1 + |} | |object Example extends App { | @@ -823,8 +841,9 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { | number: Int <- Option[Int](5) | num2: Int <- opts(2)(evidence) | _ = augmentString("abc ").stripMargin - | } yield 1 + | } yield DataType[String](number, "").next(evidence) | + | Option[Int](5).map[Int](DataType[String](_, "").next(evidence)) |} |""".stripMargin, ) @@ -878,7 +897,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object O { | type Foo3[T, R] = (T, R, "") | def hello: Option[(Int, String)] = { @@ -923,7 +942,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { _ <- server.didSave("a/src/main/scala/Main.scala")(identity) _ = assertNoDiagnostics() _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, """|object O { | def foo[Total <: Int](implicit total: ValueOf[Total]): Int = total.value | val m = foo[500](new ValueOf(...)) diff --git a/tests/unit/src/test/scala/tests/worksheets/WorksheetLspSuite.scala b/tests/unit/src/test/scala/tests/worksheets/WorksheetLspSuite.scala index a617a113cd1..5726834a4ed 100644 --- a/tests/unit/src/test/scala/tests/worksheets/WorksheetLspSuite.scala +++ b/tests/unit/src/test/scala/tests/worksheets/WorksheetLspSuite.scala @@ -112,7 +112,7 @@ class WorksheetLspSuite extends tests.BaseWorksheetLspSuite(V.scala213) { ) _ <- server.didOpen(path) _ = assertNoDiff( - client.workspaceDecorations, + client.syntheticDecorations, "new java.sql.Date(100L) // : java.sql.Date = 1970-01-01", ) } yield () @@ -150,7 +150,7 @@ class WorksheetLspSuite extends tests.BaseWorksheetLspSuite(V.scala213) { _ <- server.didOpen(path) _ = assertNoDiff( // it seems that part of the string is always different, so let's remove it - client.workspaceDecorations.replaceAll(".out\\(.*", ".out(..."), + client.syntheticDecorations.replaceAll(".out\\(.*", ".out(..."), """|import $dep.`com.typesafe.akka::akka-stream:2.6.13` | |import akka.actor.ActorSystem