@@ -17,6 +17,8 @@ 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 .NameOps .fieldName
21+ import dotty .tools .dotc .core .Names .Name
2022import dotty .tools .dotc .core .StdNames .*
2123import dotty .tools .dotc .core .Symbols .*
2224import dotty .tools .dotc .core .Types .*
@@ -116,26 +118,69 @@ class PcInlayHintsProvider(
116118 InlayHintKind .Type ,
117119 )
118120 .addDefinition(adjustedPos.start)
119- case ByNameParameters (byNameParams) =>
120- def adjustByNameParameterPos (pos : SourcePosition ): SourcePosition =
121- val adjusted = adjustPos(pos)
122- val start = text.indexWhere(! _.isWhitespace, adjusted.start)
123- val end = text.lastIndexWhere(! _.isWhitespace, adjusted.end - 1 )
121+ case Parameters (isInfixFun, args) =>
122+ def isNamedParam (pos : SourcePosition ): Boolean =
123+ val start = text.indexWhere(! _.isWhitespace, pos.start)
124+ val end = text.lastIndexWhere(! _.isWhitespace, pos.end - 1 )
124125
126+ text.slice(start, end).contains('=' )
127+
128+ def isBlockParam (pos : SourcePosition ): Boolean =
129+ val start = text.indexWhere(! _.isWhitespace, pos.start)
130+ val end = text.lastIndexWhere(! _.isWhitespace, pos.end - 1 )
125131 val startsWithBrace = text.lift(start).contains('{' )
126132 val endsWithBrace = text.lift(end).contains('}' )
127133
128- if startsWithBrace && endsWithBrace then
129- adjusted.withStart(start + 1 )
134+ startsWithBrace && endsWithBrace
135+
136+ def adjustBlockParamPos (pos : SourcePosition ): SourcePosition =
137+ if isBlockParam(pos) then
138+ pos.withStart(pos.start + 1 )
130139 else
131- adjusted
140+ pos
141+
142+ val adjustedArgs = args.map {
143+ case (name, pos, isByName) => (name, adjustPos(pos), isByName)
144+ }
145+
146+ val namedParams =
147+ if params.namedParameters() && ! isInfixFun then
148+ adjustedArgs.collect {
149+ // We don't want to show parameter names for block parameters or named parameters
150+ case (name, pos, _) if ! isBlockParam(pos) && ! isNamedParam(pos) => (name, pos)
151+ }
152+ else Nil
132153
133- byNameParams.foldLeft(inlayHints) {
134- case (ih, pos) =>
135- val adjusted = adjustByNameParameterPos(pos)
154+ val byNameParams =
155+ if params.byNameParameters() then
156+ adjustedArgs.collect {
157+ case (name, pos, isByName) if isByName => (name, pos)
158+ }
159+ else Nil
160+
161+ val namedAndByNameInlayHints =
162+ namedParams.collect {
163+ case param@ (name, pos) if byNameParams.contains(param) =>
164+ (name.toString() + " = => " , adjustBlockParamPos(pos))
165+ }
166+
167+ val namedInlayHints =
168+ namedParams.collect {
169+ case param@ (name, pos) if ! byNameParams.contains(param) =>
170+ (name.toString() + " = " , pos)
171+ }
172+
173+ val byNameInlayHints =
174+ byNameParams.collect {
175+ case param@ (_, pos) if ! namedParams.contains(param) && (! isInfixFun || (isInfixFun && isBlockParam(pos))) =>
176+ (" => " , adjustBlockParamPos(pos))
177+ }
178+
179+ (namedAndByNameInlayHints ++ namedInlayHints ++ byNameInlayHints).foldLeft(inlayHints) {
180+ case (ih, (labelStr, pos)) =>
136181 ih.add(
137- adjusted .startPos.toLsp,
138- List (LabelPart (" => " )),
182+ pos .startPos.toLsp,
183+ List (LabelPart (labelStr )),
139184 InlayHintKind .Parameter
140185 )
141186 }
@@ -412,27 +457,55 @@ object InferredType:
412457
413458end InferredType
414459
415- object ByNameParameters :
416- 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
460+ object Parameters :
461+ def unapply (tree : Tree )(using params : InlayHintsParams , ctx : Context ): Option [(Boolean , List [(Name , SourcePosition , Boolean )])] =
462+ def shouldSkipFun (fun : Tree )(using Context ): Boolean =
463+ fun match
464+ case sel : Select => isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply
465+ case _ => false
466+
467+ def isInfixFun (fun : Tree , args : List [Tree ])(using Context ): Boolean =
468+ val isInfixSelect = fun match
469+ case Select (sel, _) => sel.isInfix
470+ case _ => false
471+ val source = fun.source
472+ if args.isEmpty then isInfixSelect
473+ else
474+ (! (fun.span.end until args.head.span.start)
475+ .map(source.apply)
476+ .contains('.' ) && fun.symbol.is(Flags .ExtensionMethod )) || isInfixSelect
477+
478+ def isRealApply (tree : Tree ) =
479+ ! tree.symbol.isOneOf(Flags .GivenOrImplicit ) && ! tree.span.isZeroExtent
480+
481+ def getUnderlyingFun (tree : Tree ): Tree =
482+ tree match
483+ case Apply (fun, _) => getUnderlyingFun(fun)
484+ case TypeApply (fun, _) => getUnderlyingFun(fun)
485+ case t => t
419486
420- if (params.byNameParameters()){
487+ if (params.namedParameters() || params. byNameParameters()) then
421488 tree match
422- case Apply (TypeApply (sel : Select , _), _) if shouldSkipSelect(sel) =>
423- None
424- case Apply (sel : Select , _) if shouldSkipSelect(sel) =>
425- None
426- case Apply (fun, args) =>
427- val funTp = fun.typeOpt.widenTermRefExpr
428- val params = funTp.paramInfoss.flatten
429- Some (
430- args
431- .zip(params)
432- .collect {
433- case (tree, param) if param.isByName => tree.sourcePos
434- }
435- )
489+ case Apply (fun, args) if isRealApply(fun) =>
490+ val underlyingFun = getUnderlyingFun(fun)
491+ if shouldSkipFun(underlyingFun) then
492+ None
493+ else
494+ val funTp = fun.typeOpt.widenTermRefExpr
495+ val paramNames = funTp.paramNamess.flatten
496+ val paramInfos = funTp.paramInfoss.flatten
497+ Some (
498+ // Check if the function is an infix function or the underlying function is an infix function
499+ isInfixFun(fun, args) || underlyingFun.isInfix,
500+ (
501+ args
502+ .zip(paramNames)
503+ .zip(paramInfos)
504+ .collect {
505+ case ((arg, paramName), paramInfo) if ! arg.span.isZeroExtent => (paramName.fieldName, arg.sourcePos, paramInfo.isByName)
506+ }
507+ )
508+ )
436509 case _ => None
437- } else None
438- end ByNameParameters
510+ else None
511+ end Parameters
0 commit comments