diff --git a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala index 545607c0b8ff..b691652508d9 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala @@ -36,16 +36,20 @@ object HoverProvider: val text = params.text().nn val sourceFile = SourceFile.virtual(uri, text) driver.run(uri, sourceFile) + val unit = driver.compilationUnits.get(uri) - given ctx: Context = driver.currentCtx + given ctx: Context = + val ctx = driver.currentCtx + unit.map(ctx.fresh.setCompilationUnit).getOrElse(ctx) val pos = driver.sourcePosition(params) - val trees = driver.openedTrees(uri) + val path = unit + .map(unit => Interactive.pathTo(unit.tpdTree, pos.span)) + .getOrElse(Interactive.pathTo(driver.openedTrees(uri), pos)) val indexedContext = IndexedContext(ctx) def typeFromPath(path: List[Tree]) = if path.isEmpty then NoType else path.head.tpe - val path = Interactive.pathTo(trees, pos) val tp = typeFromPath(path) val tpw = tp.widenTermRefExpr // For expression we need to find all enclosing applies to get the exact generic type @@ -72,7 +76,10 @@ object HoverProvider: |path: |- ${path.map(_.toString()).mkString("\n- ")} |trees: - |- ${trees.map(_.toString()).mkString("\n- ")} + |- ${unit + .map(u => List(u.tpdTree)) + .getOrElse(driver.openedTrees(uri).map(_.tree)) + .map(_.toString()).mkString("\n- ")} |""".stripMargin, s"$uri::$posId" ) @@ -83,15 +90,9 @@ object HoverProvider: val skipCheckOnName = !pos.isPoint // don't check isHoveringOnName for RangeHover - val printerContext = - driver.compilationUnits.get(uri) match - case Some(unit) => - val newctx = - ctx.fresh.setCompilationUnit(unit) - Interactive.contextOfPath(enclosing)(using newctx) - case None => ctx + val printerCtx = Interactive.contextOfPath(path) val printer = ShortenedTypePrinter(search, IncludeDefaultParam.Include)( - using IndexedContext(printerContext) + using IndexedContext(printerCtx) ) MetalsInteractive.enclosingSymbolsWithExpressionType( enclosing, @@ -142,7 +143,8 @@ object HoverProvider: expressionType = Some(expressionType), symbolSignature = Some(hoverString), docstring = Some(docString), - forceExpressionType = forceExpressionType + forceExpressionType = forceExpressionType, + contextInfo = printer.getUsedRenamesInfo ) ).nn case _ => @@ -176,6 +178,7 @@ object HoverProvider: new ScalaHover( expressionType = Some(tpeString), symbolSignature = Some(s"$valOrDef $name$tpeString"), + contextInfo = printer.getUsedRenamesInfo ) ) case RefinedType(parent, _, _) => diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcSyntheticDecorationProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcSyntheticDecorationProvider.scala index 1ff410ad7f10..db70d2a7960b 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcSyntheticDecorationProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcSyntheticDecorationProvider.scala @@ -39,6 +39,8 @@ final class PcSyntheticDecorationsProvider( val source = SourceFile.virtual(filePath.toString, sourceText) driver.run(uri, source) + + given InferredType.Text = InferredType.Text(text) given ctx: Context = driver.currentCtx val unit = driver.currentCtx.run.nn.units.head @@ -219,11 +221,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 @@ -247,6 +254,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 = afterDef.indexAfterSpacesAndComments + index >= 0 && index < afterDef.size && afterDef(index) == '@' + end InferredType case class Synthetics( diff --git a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala index 9c255d20d212..0b7661e0e023 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala @@ -62,6 +62,13 @@ class ShortenedTypePrinter( AbsOverride, Lazy ) + + private val foundRenames = collection.mutable.Map.empty[Symbol, String] + + def getUsedRenamesInfo(using Context): List[String] = + foundRenames.map { (from, to) => + s"type $to = ${from.showName}" + }.toList def expressionType(tpw: Type)(using Context): Option[String] = tpw match @@ -117,8 +124,10 @@ class ShortenedTypePrinter( prefixIterator.flatMap { owner => val prefixAfterRename = ownersAfterRename(owner) + val ownerRename = indexedCtx.rename(owner) + ownerRename.foreach(rename => foundRenames += owner -> rename) val currentRenamesSearchResult = - indexedCtx.rename(owner).map(Found(owner, _, prefixAfterRename)) + ownerRename.map(Found(owner, _, prefixAfterRename)) lazy val configRenamesSearchResult = renameConfigMap.get(owner).map(Missing(owner, _, prefixAfterRename)) currentRenamesSearchResult orElse configRenamesSearchResult @@ -181,7 +190,9 @@ class ShortenedTypePrinter( override protected def selectionString(tp: NamedType): String = indexedCtx.rename(tp.symbol) match - case Some(value) => value + case Some(value) => + foundRenames += tp.symbol -> value + value case None => super.selectionString(tp) override def toText(tp: Type): Text = diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/MtagsEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/MtagsEnrichments.scala index c006dda2c652..581f131d6767 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/MtagsEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/MtagsEnrichments.scala @@ -230,6 +230,34 @@ object MtagsEnrichments extends CommonMtagsEnrichments: def stripBackticks: String = s.stripPrefix("`").stripSuffix("`") + extension (text: Array[Char]) + def indexAfterSpacesAndComments: 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 + } + extension (search: SymbolSearch) def symbolDocumentation(symbol: Symbol)(using Context diff --git a/presentation-compiler/test/dotty/tools/pc/tests/decorations/SyntheticDecorationsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/decorations/SyntheticDecorationsSuite.scala index 7d4cc3cf41a4..49ffb911aaa3 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/decorations/SyntheticDecorationsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/decorations/SyntheticDecorationsSuite.scala @@ -498,3 +498,31 @@ class SyntheticDecorationsSuite extends BaseSyntheticDecorationsSuite: |""".stripMargin ) + @Test def `val-def-with-bind` = + check( + """ + |object O { + | val tupleBound @ (one, two) = ("1", "2") + |} + |""".stripMargin, + """ + |object O { + | val tupleBound @ (one: String, two: String) = ("1", "2") + |} + |""".stripMargin + ) + + @Test def `val-def-with-bind-and-comment` = + check( + """ + |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/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala index d6707c54894e..f12cab7e65ef 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala @@ -789,6 +789,28 @@ class InsertInferredTypeSuite extends BaseCodeActionSuite: |""".stripMargin ) + @Test def `import-rename` = + checkEdit( + """ + |package a + |import scala.collection.{AbstractMap => AB} + | + |object Main { + | def test(): AB[Int, String] = ??? + | val <> = test() + |} + |""".stripMargin, + """ + |package a + |import scala.collection.{AbstractMap => AB} + | + |object Main { + | def test(): AB[Int, String] = ??? + | val x: AB[Int, String] = test() + |} + |""".stripMargin + ) + def checkEdit( original: String, expected: String diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDefnSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDefnSuite.scala index 84af8f21f258..7a647fa40f5f 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDefnSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDefnSuite.scala @@ -163,8 +163,7 @@ class HoverDefnSuite extends BaseHoverSuite: """package b.p@@kg |object Main |""".stripMargin, - // TODO, doesn's show information on packages - "" + "package b.pkg".hover, ) @Test def `pat-bind` = diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala index cf4682bd9a11..bd044b55528a 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala @@ -419,7 +419,8 @@ class HoverTermSuite extends BaseHoverSuite: |object MyIntOut: | extension (i: MyIntOut) def uneven = i.value % 2 == 1 | - |val a = MyIntOut(1).un@@even + |object Test: + | val a = MyIntOut(1).un@@even |""".stripMargin, """extension (i: MyIntOut) def uneven: Boolean |""".stripMargin.hover @@ -593,4 +594,46 @@ class HoverTermSuite extends BaseHoverSuite: |extension [A](self: A) def inferredTypeArg[C](value: C): C |``` |""".stripMargin - ) \ No newline at end of file + ) + + @Test def `import-rename` = + check( + """ + |import scala.collection.{AbstractMap => AB} + |import scala.collection.{Set => S} + | + |object Main { + | def test(): AB[Int, String] = ??? + | <> + |} + |""".stripMargin, + """ + |```scala + |type AB = AbstractMap + |``` + | + |```scala + |val tt: AB[Int, String] + |```""".stripMargin, + ) + + @Test def `import-rename2` = + check( + """ + |import scala.collection.{AbstractMap => AB} + |import scala.collection.{Set => S} + | + |object Main { + | <> + |} + |""".stripMargin, + """ + |```scala + |type S = Set + |type AB = AbstractMap + |``` + | + |```scala + |def test(d: S[Int], f: S[Char]): AB[Int, String] + |```""".stripMargin, + ) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTypeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTypeSuite.scala index 2157aa891bae..4a5c81b74720 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTypeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTypeSuite.scala @@ -362,7 +362,8 @@ class HoverTypeSuite extends BaseHoverSuite: |object MyIntOut: | extension (i: MyIntOut) def uneven = i.value % 2 == 1 | - |val a = MyIntOut(1).un@@even + |object Test: + | val a = MyIntOut(1).un@@even |""".stripMargin, """|extension (i: MyIntOut) def uneven: Boolean |""".stripMargin.hover, diff --git a/project/Build.scala b/project/Build.scala index 0e3f725bb180..7a650b2943ee 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1341,7 +1341,7 @@ object Build { BuildInfoPlugin.buildInfoDefaultSettings lazy val presentationCompilerSettings = { - val mtagsVersion = "1.2.0+54-1a664e80-SNAPSHOT" + val mtagsVersion = "1.2.0+67-30f8ab53-SNAPSHOT" Seq( resolvers ++= Resolver.sonatypeOssRepos("snapshots"),