From 02ab6b797ffa5c5078dac5f257b4a6e59fbcd2e3 Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Fri, 1 Dec 2023 12:01:40 +0100 Subject: [PATCH] bugfix: don't show inferred type for val def bind (#5891) --- .../pc/PcSyntheticDecorationsProvider.scala | 12 ++++- .../pc/PcSyntheticDecorationProvider.scala | 18 +++++++- .../mtags/ScalametaCommonEnrichments.scala | 27 +++++++++++ .../tests/pc/SyntheticDecorationsSuite.scala | 24 ++++++++++ .../test/scala/tests/SkipCommentsSuite.scala | 46 +++++++++++++++++++ .../SyntheticDecorationsLspSuite.scala | 2 +- 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 tests/unit/src/test/scala/tests/SkipCommentsSuite.scala 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 42fb9bb68dd..37d047b3482 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 @@ -152,7 +152,8 @@ final class PcSyntheticDecorationsProvider( if hasMissingTypeAnnot(vd, tpt) && !primaryConstructorParam(vd.symbol) && isNotInUnapply(vd) && - !isCompilerGeneratedSymbol(vd.symbol) => + !isCompilerGeneratedSymbol(vd.symbol) && + !isValDefBind(vd) => Some(vd.symbol.tpe.widen.finalResultType, vd.namePosition) case dd @ DefDef(_, _, _, _, tpt, _) if hasMissingTypeAnnot(dd, tpt) && @@ -191,6 +192,15 @@ final class PcSyntheticDecorationsProvider( private def isNotInUnapply(vd: ValDef) = !vd.rhs.pos.isRange || vd.rhs.pos.start > vd.namePosition.end + + /* If is left part of val definition bind: + * val <> @ ... = + */ + private def isValDefBind(vd: ValDef) = { + val afterDef = text.drop(vd.namePosition.end) + val index = indexAfterSpacesAndComments(afterDef) + index >= 0 && index < afterDef.size && afterDef(index) == '@' + } } private def syntheticTupleApply(sel: Select): Boolean = { 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 ac15b51ed60..9ac177f1b76 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 @@ -37,6 +37,7 @@ class PcSyntheticDecorationsProvider( driver.run(uri, source) given ctx: Context = driver.currentCtx val unit = driver.currentCtx.run.units.head + given InferredType.Text = InferredType.Text(text) def tpdTree = unit.tpdTree def provide(): List[SyntheticDecoration] = @@ -217,11 +218,16 @@ object TypeParameters: end TypeParameters object InferredType: - def unapply(tree: Tree)(using Context) = + opaque type Text = Array[Char] + object Text: + def apply(text: Array[Char]): Text = text + + def unapply(tree: Tree)(using text: Text, cxt: Context) = tree match case vd @ ValDef(_, tpe, _) if isValidSpan(tpe.span, vd.nameSpan) && - !vd.symbol.is(Flags.Enum) => + !vd.symbol.is(Flags.Enum) && + !isValDefBind(text, vd) => if vd.symbol == vd.symbol.sourceSymbol then Some(tpe.tpe, tpe.sourcePos.withSpan(vd.nameSpan), vd) else None @@ -245,6 +251,14 @@ object InferredType: nameSpan.exists && !nameSpan.isZeroExtent + /* If is left part of val definition bind: + * val <> @ ... = + */ + def isValDefBind(text: Text, vd: ValDef)(using Context) = + val afterDef = text.drop(vd.nameSpan.end) + val index = indexAfterSpacesAndComments(afterDef) + index >= 0 && index < afterDef.size && afterDef(index) == '@' + end InferredType case class Synthetics( diff --git a/mtags/src/main/scala/scala/meta/internal/mtags/ScalametaCommonEnrichments.scala b/mtags/src/main/scala/scala/meta/internal/mtags/ScalametaCommonEnrichments.scala index eb14ec1489c..af5ee1d9eec 100644 --- a/mtags/src/main/scala/scala/meta/internal/mtags/ScalametaCommonEnrichments.scala +++ b/mtags/src/main/scala/scala/meta/internal/mtags/ScalametaCommonEnrichments.scala @@ -33,6 +33,33 @@ import org.eclipse.{lsp4j => l} object ScalametaCommonEnrichments extends ScalametaCommonEnrichments {} trait ScalametaCommonEnrichments extends CommonMtagsEnrichments { + def indexAfterSpacesAndComments(text: Array[Char]): Int = { + var isInComment = false + var startedStateChange = false + val index = text.indexWhere { + case '/' if !isInComment && !startedStateChange => + startedStateChange = true + false + case '*' if !isInComment && startedStateChange => + startedStateChange = false + isInComment = true + false + case '/' if isInComment && startedStateChange => + startedStateChange = false + isInComment = false + false + case '*' if isInComment && !startedStateChange => + startedStateChange = true + false + case c if isInComment || c.isSpaceChar || c == '\t' => + startedStateChange = false + false + case _ => true + } + if (startedStateChange) index - 1 + else index + } + private def logger: Logger = Logger.getLogger(classOf[ScalametaCommonEnrichments].getName) diff --git a/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala b/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala index d43b38059c7..c2c20b64d7b 100644 --- a/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/SyntheticDecorationsSuite.scala @@ -566,4 +566,28 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite { |} |""".stripMargin ) + + check( + "val-def-with-bind", + """|object O { + | val tupleBound @ (one, two) = ("1", "2") + |} + |""".stripMargin, + """|object O { + | val tupleBound @ (one: String, two: String) = ("1", "2") + |} + |""".stripMargin + ) + + check( + "val-def-with-bind-and-comment", + """|object O { + | val tupleBound /* comment */ @ (one, two) = ("1", "2") + |} + |""".stripMargin, + """|object O { + | val tupleBound /* comment */ @ (one: String, two: String) = ("1", "2") + |} + |""".stripMargin + ) } diff --git a/tests/unit/src/test/scala/tests/SkipCommentsSuite.scala b/tests/unit/src/test/scala/tests/SkipCommentsSuite.scala new file mode 100644 index 00000000000..aee11bb4c69 --- /dev/null +++ b/tests/unit/src/test/scala/tests/SkipCommentsSuite.scala @@ -0,0 +1,46 @@ +package tests + +import scala.meta.internal.metals.MetalsEnrichments._ + +import munit.TestOptions + +class SkipCommentsSuite extends munit.FunSuite with Assertions { + + check( + "drop-all", + " /* bhjv */ /* bhjbi */", + ) + + check( + "between-comments", + " /* bhjv */ @ /* bhjbi */", + Some('@'), + ) + + check( + "not-comment", + " /@", + Some('/'), + ) + + check( + "tab", + "\t /*cbu * whec*/", + ) + + def check( + name: TestOptions, + text: String, + nextChar: Option[Char] = None, + ): Unit = + test(name) { + val index = indexAfterSpacesAndComments(text.toCharArray()) + def clue = s"text: $text, index: $index" + nextChar match { + case None => assert(index < 0 || index >= text.size, clue) + case Some(c) => + assertEquals(text.charAt(index), c, clue) + } + } + +} diff --git a/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala b/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala index 59488221d7b..0b02156f514 100644 --- a/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala +++ b/tests/unit/src/test/scala/tests/decorations/SyntheticDecorationsLspSuite.scala @@ -494,7 +494,7 @@ class SyntheticDecorationsLspSuite extends BaseLspSuite("implicits") { | val List[Int](l1: Int, l2: Int) = List[Int](12, 13) | println("Hello!") | val abc: Int = 123 - | val tupleBound: (String, String) @ (one: String, two: String) = ("1", "2") + | val tupleBound @ (one: String, two: String) = ("1", "2") | val tupleExplicit: (String, String) = Tuple2[String, String]("1", "2") | val tupleExplicitApply: (String, String) = Tuple2.apply[String, String]("1", "2") | var variable: Int = 123