@@ -17,6 +17,7 @@ import scala.meta.pc.SymbolSearch
1717import dotty .tools .dotc .ast .tpd .*
1818import dotty .tools .dotc .core .Contexts .Context
1919import dotty .tools .dotc .core .Flags
20+ import dotty .tools .dotc .core .Names .Name
2021import dotty .tools .dotc .core .StdNames .*
2122import dotty .tools .dotc .core .Symbols .*
2223import dotty .tools .dotc .core .Types .*
@@ -29,6 +30,7 @@ import dotty.tools.dotc.util.Spans.Span
2930import org .eclipse .lsp4j .InlayHint
3031import org .eclipse .lsp4j .InlayHintKind
3132import org .eclipse .{lsp4j as l }
33+ import dotty .tools .dotc .core .NameOps .fieldName
3234
3335class PcInlayHintsProvider (
3436 driver : InteractiveDriver ,
@@ -116,8 +118,8 @@ class PcInlayHintsProvider(
116118 InlayHintKind .Type ,
117119 )
118120 .addDefinition(adjustedPos.start)
119- case ByNameParameters (byNameParams ) =>
120- def adjustByNameParameterPos (pos : SourcePosition ): SourcePosition =
121+ case NamedParameters (_) | ByNameParameters (_ ) =>
122+ def adjustBlockParameterPosOpt (pos : SourcePosition ): Option [ SourcePosition ] =
121123 val adjusted = adjustPos(pos)
122124 val start = text.indexWhere(! _.isWhitespace, adjusted.start)
123125 val end = text.lastIndexWhere(! _.isWhitespace, adjusted.end - 1 )
@@ -126,16 +128,51 @@ class PcInlayHintsProvider(
126128 val endsWithBrace = text.lift(end).contains('}' )
127129
128130 if startsWithBrace && endsWithBrace then
129- adjusted.withStart(start + 1 )
131+ Some ( adjusted.withStart(start + 1 ) )
130132 else
131- adjusted
133+ None
134+
135+ def adjustParameterPos (pos : SourcePosition ): SourcePosition =
136+ adjustBlockParameterPosOpt(pos) match
137+ case Some (adjusted) => adjusted
138+ case None => adjustPos(pos)
139+
140+ def isNamedParameter (pos : SourcePosition ): Boolean =
141+ val adjusted = adjustPos(pos)
142+ val start = text.indexWhere(! _.isWhitespace, adjusted.start)
143+ val end = text.lastIndexWhere(! _.isWhitespace, adjusted.end - 1 )
144+ text.slice(start, end).contains('=' )
145+
146+ val namedParams = NamedParameters .unapply(tree).getOrElse(Nil ).collect {
147+ // We don't want to show parameter names for block parameters or named parameters
148+ case (name, pos) if adjustBlockParameterPosOpt(pos).isEmpty && ! isNamedParameter(pos) => (name, pos)
149+ }
150+ val byNameParams = ByNameParameters .unapply(tree).getOrElse(Nil )
151+
152+ val namedAndByNameInlayHints =
153+ namedParams.collect {
154+ case (name, pos) if byNameParams.contains(pos) =>
155+ (name.toString() + " = => " , adjustParameterPos(pos))
156+ }
157+
158+ val namedInlayHints =
159+ namedParams.collect {
160+ case (name, pos) if ! byNameParams.contains(pos) =>
161+ (name.toString() + " = " , adjustParameterPos(pos))
162+ }
163+
164+ val namedParamsPos = namedParams.map(_._2)
165+ val byNameInlayHints =
166+ byNameParams.collect {
167+ case pos if ! namedParamsPos.contains(pos) =>
168+ (" => " , adjustParameterPos(pos))
169+ }
132170
133- byNameParams.foldLeft(inlayHints) {
134- case (ih, pos) =>
135- val adjusted = adjustByNameParameterPos(pos)
171+ (namedAndByNameInlayHints ++ namedInlayHints ++ byNameInlayHints).foldLeft(inlayHints) {
172+ case (ih, (labelStr, pos)) =>
136173 ih.add(
137- adjusted .startPos.toLsp,
138- List (LabelPart (" => " )),
174+ pos .startPos.toLsp,
175+ List (LabelPart (labelStr )),
139176 InlayHintKind .Parameter
140177 )
141178 }
@@ -414,16 +451,11 @@ end InferredType
414451
415452object ByNameParameters :
416453 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()){
454+ if (params.byNameParameters()) {
421455 tree match
422- case Apply (TypeApply (sel : Select , _), _) if shouldSkipSelect(sel) =>
423- None
424- case Apply (sel : Select , _) if shouldSkipSelect(sel) =>
456+ case FlattenApplies (sel : Select , args) if SkipRules .shouldSkipSelect(sel, args) =>
425457 None
426- case Apply (fun, args) =>
458+ case Apply (fun, args) if ! SkipRules .shouldSkipInfix(fun, args) =>
427459 val funTp = fun.typeOpt.widenTermRefExpr
428460 val params = funTp.paramInfoss.flatten
429461 Some (
@@ -436,3 +468,51 @@ object ByNameParameters:
436468 case _ => None
437469 } else None
438470end ByNameParameters
471+
472+ object NamedParameters :
473+ def unapply (tree : Tree )(using params : InlayHintsParams , ctx : Context ): Option [List [(Name , SourcePosition )]] =
474+ def isRealApply (tree : Tree ) =
475+ ! tree.symbol.isOneOf(Flags .GivenOrImplicit ) && ! tree.span.isZeroExtent
476+ if (params.namedParameters()){
477+ tree match
478+ case FlattenApplies (sel : Select , args) if SkipRules .shouldSkipSelect(sel, args) =>
479+ None
480+ case Apply (fun, args) if isRealApply(fun) && ! SkipRules .shouldSkipInfix(fun, args) =>
481+ val funTp = fun.typeOpt.widenTermRefExpr
482+ val params = funTp.paramNamess.flatten
483+ Some (
484+ args
485+ .zip(params)
486+ .collect {
487+ case (arg, param) if ! arg.span.isZeroExtent => (param.fieldName, arg.sourcePos)
488+ }
489+ )
490+ case _ => None
491+ } else None
492+ end NamedParameters
493+
494+ private object SkipRules :
495+ def shouldSkipSelect (sel : Select , args : List [Tree ])(using Context ): Boolean =
496+ isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply || sel.isInfix
497+
498+ def shouldSkipInfix (fun : Tree , args : List [Tree ])(using Context ): Boolean =
499+ val source = fun.source
500+ if args.isEmpty then false
501+ else
502+ val isInfixExtensionMethod =
503+ ! (fun.span.end until args.head.span.start)
504+ .map(source.apply)
505+ .contains('.' )
506+ isInfixExtensionMethod && fun.symbol.is(Flags .ExtensionMethod )
507+
508+ private object FlattenApplies :
509+ /*
510+ * Extractor that strips away a (possibly nested) chain of `Apply` / `TypeApply`
511+ * wrappers and returns the underlying function tree.
512+ */
513+ def unapply (tree : Tree ): (Tree , List [Tree ]) =
514+ tree match
515+ case Apply (FlattenApplies (fun, argss), args) => (fun, argss ++: args)
516+ case TypeApply (FlattenApplies (fun, argss), args) => (fun, argss ++: args)
517+ case t => (t, Nil )
518+ end FlattenApplies
0 commit comments