@@ -17,6 +17,7 @@ import scala.meta.pc.SymbolSearch
17
17
import dotty .tools .dotc .ast .tpd .*
18
18
import dotty .tools .dotc .core .Contexts .Context
19
19
import dotty .tools .dotc .core .Flags
20
+ import dotty .tools .dotc .core .Names .Name
20
21
import dotty .tools .dotc .core .StdNames .*
21
22
import dotty .tools .dotc .core .Symbols .*
22
23
import dotty .tools .dotc .core .Types .*
@@ -29,6 +30,7 @@ import dotty.tools.dotc.util.Spans.Span
29
30
import org .eclipse .lsp4j .InlayHint
30
31
import org .eclipse .lsp4j .InlayHintKind
31
32
import org .eclipse .{lsp4j as l }
33
+ import dotty .tools .dotc .core .NameOps .fieldName
32
34
33
35
class PcInlayHintsProvider (
34
36
driver : InteractiveDriver ,
@@ -116,8 +118,8 @@ class PcInlayHintsProvider(
116
118
InlayHintKind .Type ,
117
119
)
118
120
.addDefinition(adjustedPos.start)
119
- case ByNameParameters (byNameParams ) =>
120
- def adjustByNameParameterPos (pos : SourcePosition ): SourcePosition =
121
+ case NamedParameters (_) | ByNameParameters (_ ) =>
122
+ def adjustBlockParameterPos (pos : SourcePosition ): SourcePosition =
121
123
val adjusted = adjustPos(pos)
122
124
val start = text.indexWhere(! _.isWhitespace, adjusted.start)
123
125
val end = text.lastIndexWhere(! _.isWhitespace, adjusted.end - 1 )
@@ -130,12 +132,33 @@ class PcInlayHintsProvider(
130
132
else
131
133
adjusted
132
134
133
- byNameParams.foldLeft(inlayHints) {
134
- case (ih, pos) =>
135
- val adjusted = adjustByNameParameterPos(pos)
135
+ val namedParams = NamedParameters .unapply(tree).getOrElse(Nil )
136
+ val byNameParams = ByNameParameters .unapply(tree).getOrElse(Nil )
137
+
138
+ val namedAndByNameInlayHints =
139
+ namedParams.collect {
140
+ case (name, pos) if byNameParams.contains(pos) =>
141
+ (name.toString() + " = => " , adjustBlockParameterPos(pos))
142
+ }
143
+
144
+ val namedInlayHints =
145
+ namedParams.collect {
146
+ case (name, pos) if ! byNameParams.contains(pos) =>
147
+ (name.toString() + " = " , adjustBlockParameterPos(pos))
148
+ }
149
+
150
+ val namedParamsPos = namedParams.map(_._2)
151
+ val byNameInlayHints =
152
+ byNameParams.collect {
153
+ case pos if ! namedParamsPos.contains(pos) =>
154
+ (" => " , adjustBlockParameterPos(pos))
155
+ }
156
+
157
+ (namedAndByNameInlayHints ++ namedInlayHints ++ byNameInlayHints).foldLeft(inlayHints) {
158
+ case (ih, (labelStr, pos)) =>
136
159
ih.add(
137
- adjusted .startPos.toLsp,
138
- List (LabelPart (" => " )),
160
+ pos .startPos.toLsp,
161
+ List (LabelPart (labelStr )),
139
162
InlayHintKind .Parameter
140
163
)
141
164
}
@@ -414,14 +437,9 @@ end InferredType
414
437
415
438
object ByNameParameters :
416
439
def unapply (tree : Tree )(using params : InlayHintsParams , ctx : Context ): Option [List [SourcePosition ]] =
417
- def shouldSkipSelect (sel : Select ) =
418
- isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply
419
-
420
- if (params.byNameParameters()){
440
+ if (params.byNameParameters()) {
421
441
tree match
422
- case Apply (TypeApply (sel : Select , _), _) if shouldSkipSelect(sel) =>
423
- None
424
- case Apply (sel : Select , _) if shouldSkipSelect(sel) =>
442
+ case FlattenApplies (sel : Select ) if SkipRules .shouldSkipSelect(sel) =>
425
443
None
426
444
case Apply (fun, args) =>
427
445
val funTp = fun.typeOpt.widenTermRefExpr
@@ -436,3 +454,50 @@ object ByNameParameters:
436
454
case _ => None
437
455
} else None
438
456
end ByNameParameters
457
+
458
+ object NamedParameters :
459
+ def unapply (tree : Tree )(using params : InlayHintsParams , ctx : Context ): Option [List [(Name , SourcePosition )]] =
460
+ def isSingleBlock (args : List [Tree ]): Boolean =
461
+ args.size == 1 && args.forall {
462
+ case _ : Block => true
463
+ case Typed (_ : Block , _) => true
464
+ case _ => false
465
+ }
466
+
467
+ def isRealApply (tree : Tree ) =
468
+ ! tree.symbol.isOneOf(Flags .GivenOrImplicit ) && ! tree.span.isZeroExtent
469
+
470
+ if (params.namedParameters()){
471
+ tree match
472
+ case FlattenApplies (sel : Select ) if SkipRules .shouldSkipSelect(sel) =>
473
+ None
474
+ case Apply (fun, args) if isRealApply(fun) =>
475
+ val funTp = fun.typeOpt.widenTermRefExpr
476
+ val params = funTp.paramNamess.flatten
477
+ Some (
478
+ args
479
+ .zip(params)
480
+ .collect {
481
+ case (tree, paramName) if ! tree.span.isZeroExtent => (paramName.fieldName, tree.sourcePos)
482
+ }
483
+ )
484
+ case _ => None
485
+ } else None
486
+ end NamedParameters
487
+
488
+ object SkipRules :
489
+ def shouldSkipSelect (sel : Select )(using Context ): Boolean =
490
+ isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply || sel.isInfix
491
+
492
+
493
+ object FlattenApplies :
494
+ /*
495
+ * Extractor that strips away a (possibly nested) chain of `Apply` / `TypeApply`
496
+ * wrappers and returns the underlying function tree.
497
+ */
498
+ def unapply (tree : Tree ): Option [Tree ] =
499
+ tree match
500
+ case Apply (FlattenApplies (fun), _) => Some (fun)
501
+ case TypeApply (FlattenApplies (fun), _) => Some (fun)
502
+ case t => Some (t)
503
+ end FlattenApplies
0 commit comments