@@ -6,18 +6,18 @@ import java.nio.file.Paths
66import scala .meta .internal .metals .ReportContext
77import dotty .tools .pc .utils .MtagsEnrichments .*
88import dotty .tools .pc .printer .ShortenedTypePrinter
9+ import scala .meta .internal .pc .InlayHints
10+ import scala .meta .internal .pc .LabelPart
11+ import scala .meta .internal .pc .LabelPart .*
12+ import scala .meta .pc .InlayHintsParams
913import scala .meta .pc .SymbolSearch
10- import scala .meta .pc .SyntheticDecoration
11- import scala .meta .pc .SyntheticDecorationsParams
12- import scala .meta .internal .pc .DecorationKind
13- import scala .meta .internal .pc .Decoration
14-
1514
1615import dotty .tools .dotc .ast .tpd
1716import dotty .tools .dotc .ast .tpd .*
1817import dotty .tools .dotc .core .Contexts .Context
1918import dotty .tools .dotc .core .Flags
2019import dotty .tools .dotc .core .StdNames .*
20+ import dotty .tools .dotc .core .Symbols .*
2121import dotty .tools .dotc .core .Types .*
2222import dotty .tools .dotc .interactive .Interactive
2323import dotty .tools .dotc .interactive .InteractiveDriver
@@ -26,9 +26,13 @@ import dotty.tools.dotc.util.SourcePosition
2626import dotty .tools .dotc .util .Spans .Span
2727import dotty .tools .pc .IndexedContext
2828
29- final class PcSyntheticDecorationsProvider (
29+ import org .eclipse .lsp4j .InlayHint
30+ import org .eclipse .lsp4j .InlayHintKind
31+ import org .eclipse .{lsp4j as l }
32+
33+ class PcInlayHintsProvider (
3034 driver : InteractiveDriver ,
31- params : SyntheticDecorationsParams ,
35+ params : InlayHintsParams ,
3236 symbolSearch : SymbolSearch ,
3337)(using ReportContext ):
3438
@@ -43,75 +47,81 @@ final class PcSyntheticDecorationsProvider(
4347 given InferredType .Text = InferredType .Text (text)
4448 given ctx : Context = driver.currentCtx
4549 val unit = driver.currentCtx.run.nn.units.head
50+ val pos = driver.sourcePosition(params)
4651
47- def tpdTree = unit.tpdTree
52+ def provide (): List [InlayHint ] =
53+ val deepFolder = DeepFolder [InlayHints ](collectDecorations)
54+ Interactive
55+ .pathTo(driver.openedTrees(uri), pos)(using driver.currentCtx)
56+ .headOption
57+ .getOrElse(unit.tpdTree)
58+ .enclosedChildren(pos.span)
59+ .flatMap(tpdTree => deepFolder(InlayHints .empty, tpdTree).result())
4860
49- def provide (): List [SyntheticDecoration ] =
50- val deepFolder = DeepFolder [Synthetics ](collectDecorations)
51- deepFolder(Synthetics .empty, tpdTree).result()
61+ private def adjustPos (pos : SourcePosition ): SourcePosition =
62+ pos.adjust(text)._1
5263
5364 def collectDecorations (
54- decorations : Synthetics ,
65+ inlayHints : InlayHints ,
5566 tree : Tree ,
56- ): Synthetics =
67+ ): InlayHints =
5768 tree match
58- case ImplicitConversion (name , range) if params.implicitConversions() =>
59- val adjusted = range.adjust(text)._1
60- decorations
69+ case ImplicitConversion (symbol , range) if params.implicitConversions() =>
70+ val adjusted = adjustPos(range)
71+ inlayHints
6172 .add(
62- Decoration (
63- adjusted.startPos.toLsp,
64- name + " (" ,
65- DecorationKind .ImplicitConversion ,
66- )
73+ adjusted.startPos.toLsp,
74+ labelPart(symbol, symbol.decodedName) :: LabelPart (" (" ) :: Nil ,
75+ InlayHintKind .Parameter ,
6776 )
6877 .add(
69- Decoration (
70- adjusted.endPos.toLsp,
71- " )" ,
72- DecorationKind .ImplicitConversion ,
73- )
78+ adjusted.endPos.toLsp,
79+ LabelPart (" )" ) :: Nil ,
80+ InlayHintKind .Parameter ,
7481 )
75- case ImplicitParameters (names , pos, allImplicit)
82+ case ImplicitParameters (symbols , pos, allImplicit)
7683 if params.implicitParameters() =>
84+ val labelParts = symbols.map(s => List (labelPart(s, s.decodedName)))
7785 val label =
78- if allImplicit then names.mkString(" (" , " , " , " )" )
79- else names.mkString(" , " , " , " , " " )
80- decorations.add(
81- Decoration (
82- pos.adjust(text)._1.toLsp,
83- label,
84- DecorationKind .ImplicitParameter ,
85- )
86+ if allImplicit then labelParts.separated(" (" , " , " , " )" )
87+ else labelParts.separated(" , " )
88+ inlayHints.add(
89+ adjustPos(pos).toLsp,
90+ label,
91+ InlayHintKind .Parameter ,
92+ )
93+ case ValueOf (label, pos) if params.implicitParameters() =>
94+ inlayHints.add(
95+ adjustPos(pos).toLsp,
96+ LabelPart (" (" ) :: LabelPart (label) :: List (LabelPart (" )" )),
97+ InlayHintKind .Parameter ,
8698 )
8799 case TypeParameters (tpes, pos, sel)
88100 if params.typeParameters() && ! syntheticTupleApply(sel) =>
89- val label = tpes.map(toLabel(_, pos)).mkString(" [" , " , " , " ]" )
90- decorations.add(
91- Decoration (
92- pos.adjust(text)._1.endPos.toLsp,
93- label,
94- DecorationKind .TypeParameter ,
95- )
101+ val label = tpes.map(toLabelParts(_, pos)).separated(" [" , " , " , " ]" )
102+ inlayHints.add(
103+ adjustPos(pos).endPos.toLsp,
104+ label,
105+ InlayHintKind .Type ,
96106 )
97- case InferredType (tpe, pos, defTree) if params.inferredTypes() =>
98- val adjustedPos = pos.adjust(text)._1.endPos
99- if decorations.containsDef(adjustedPos.start) then decorations
107+ case InferredType (tpe, pos, defTree)
108+ if params.inferredTypes() && ! isErrorTpe(tpe) =>
109+ val adjustedPos = adjustPos(pos).endPos
110+ if inlayHints.containsDef(adjustedPos.start) then inlayHints
100111 else
101- decorations.add(
102- Decoration (
112+ inlayHints
113+ .add (
103114 adjustedPos.toLsp,
104- " : " + toLabel(tpe, pos),
105- DecorationKind .InferredType ,
106- ),
107- adjustedPos.start,
108- )
109- case _ => decorations
115+ LabelPart (" : " ) :: toLabelParts(tpe, pos),
116+ InlayHintKind .Type ,
117+ )
118+ .addDefinition(adjustedPos.start)
119+ case _ => inlayHints
110120
111- private def toLabel (
121+ private def toLabelParts (
112122 tpe : Type ,
113123 pos : SourcePosition ,
114- ): String =
124+ ): List [ LabelPart ] =
115125 val tpdPath =
116126 Interactive .pathTo(unit.tpdTree, pos.span)
117127
@@ -129,13 +139,15 @@ final class PcSyntheticDecorationsProvider(
129139 case AppliedType (tycon, args) =>
130140 isInScope(tycon) && args.forall(isInScope)
131141 case _ => true
132- if isInScope(tpe)
133- then tpe
142+ if isInScope(tpe) then tpe
134143 else tpe.metalsDealias(using indexedCtx.ctx)
135144
136145 val dealiased = optDealias(tpe)
137- printer.tpe(dealiased)
138- end toLabel
146+ val tpeStr = printer.tpe(dealiased)
147+ val usedRenames = printer.getUsedRenames
148+ val parts = partsFromType(dealiased, usedRenames)
149+ InlayHints .makeLabelParts(parts, tpeStr)
150+ end toLabelParts
139151
140152 private val definitions = IndexedContext (ctx).ctx.definitions
141153 private def syntheticTupleApply (tree : Tree ): Boolean =
@@ -152,7 +164,32 @@ final class PcSyntheticDecorationsProvider(
152164 case _ => true
153165 else false
154166 case _ => false
155- end PcSyntheticDecorationsProvider
167+
168+ private def labelPart (symbol : Symbol , label : String ) =
169+ if symbol.source == pos.source then
170+ LabelPart (
171+ label,
172+ pos = Some (symbol.sourcePos.toLsp.getStart().nn),
173+ )
174+ else
175+ LabelPart (
176+ label,
177+ symbol = SemanticdbSymbols .symbolName(symbol),
178+ )
179+
180+ private def partsFromType (
181+ tpe : Type ,
182+ usedRenames : Map [Symbol , String ],
183+ ): List [LabelPart ] =
184+ NamedPartsAccumulator (_ => true )(Nil , tpe)
185+ .filter(_.symbol != NoSymbol )
186+ .map { t =>
187+ val label = usedRenames.get(t.symbol).getOrElse(t.symbol.decodedName)
188+ labelPart(t.symbol, label)
189+ }
190+
191+ private def isErrorTpe (tpe : Type ): Boolean = tpe.isError
192+ end PcInlayHintsProvider
156193
157194object ImplicitConversion :
158195 def unapply (tree : Tree )(using Context ) =
@@ -170,7 +207,7 @@ object ImplicitConversion:
170207 val lastArgPos =
171208 args.lastOption.map(_.sourcePos).getOrElse(fun.sourcePos)
172209 Some (
173- fun.symbol.decodedName ,
210+ fun.symbol,
174211 lastArgPos.withStart(fun.sourcePos.start),
175212 )
176213end ImplicitConversion
@@ -183,23 +220,29 @@ object ImplicitParameters:
183220 val (implicitArgs, providedArgs) = args.partition(isSyntheticArg)
184221 val allImplicit = providedArgs.isEmpty
185222 val pos = implicitArgs.head.sourcePos
186- Some (implicitArgs.map(_.symbol.decodedName), pos, allImplicit)
223+ Some (implicitArgs.map(_.symbol), pos, allImplicit)
224+ case _ => None
225+
226+ private def isSyntheticArg (tree : Tree )(using Context ) = tree match
227+ case tree : Ident =>
228+ tree.span.isSynthetic && tree.symbol.isOneOf(Flags .GivenOrImplicit )
229+ case _ => false
230+ end ImplicitParameters
231+
232+ object ValueOf :
233+ def unapply (tree : Tree )(using Context ) =
234+ tree match
187235 case Apply (ta @ TypeApply (fun, _), _)
188236 if fun.span.isSynthetic && isValueOf(fun) =>
189237 Some (
190- List ( " new " + tpnme.valueOf.decoded.capitalize + " (...)" ) ,
238+ " new " + tpnme.valueOf.decoded.capitalize + " (...)" ,
191239 fun.sourcePos,
192- true ,
193240 )
194241 case _ => None
195242 private def isValueOf (tree : Tree )(using Context ) =
196243 val symbol = tree.symbol.maybeOwner
197244 symbol.name.decoded == tpnme.valueOf.decoded.capitalize
198- private def isSyntheticArg (tree : Tree )(using Context ) = tree match
199- case tree : Ident =>
200- tree.span.isSynthetic && tree.symbol.isOneOf(Flags .GivenOrImplicit )
201- case _ => false
202- end ImplicitParameters
245+ end ValueOf
203246
204247object TypeParameters :
205248 def unapply (tree : Tree )(using Context ) =
@@ -259,35 +302,7 @@ object InferredType:
259302 */
260303 def isValDefBind (text : Text , vd : ValDef )(using Context ) =
261304 val afterDef = text.drop(vd.nameSpan.end)
262- val index = afterDef. indexAfterSpacesAndComments
305+ val index = indexAfterSpacesAndComments(afterDef)
263306 index >= 0 && index < afterDef.size && afterDef(index) == '@'
264307
265308end InferredType
266-
267- case class Synthetics (
268- decorations : List [Decoration ],
269- definitions : Set [Int ],
270- ):
271- def containsDef (offset : Int ) = definitions(offset)
272- def add (decoration : Decoration , offset : Int ) =
273- copy(
274- decorations = addDecoration(decoration),
275- definitions = definitions + offset,
276- )
277- def add (decoration : Decoration ) =
278- copy (
279- decorations = addDecoration(decoration)
280- )
281-
282- // If method has both type parameter and implicit parameter, we want the type parameter decoration to be displayed first,
283- // but it's added second. This method adds the decoration to the right position in the list.
284- private def addDecoration (decoration : Decoration ): List [Decoration ] =
285- val atSamePos =
286- decorations.takeWhile(_.range.getStart() == decoration.range.getStart())
287- (atSamePos :+ decoration) ++ decorations.drop(atSamePos.size)
288-
289- def result (): List [Decoration ] = decorations.reverse
290- end Synthetics
291-
292- object Synthetics :
293- def empty : Synthetics = Synthetics (Nil , Set .empty)
0 commit comments