@@ -17,6 +17,8 @@ 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 .NameOps .fieldName
21
+ import dotty .tools .dotc .core .Names .Name
20
22
import dotty .tools .dotc .core .StdNames .*
21
23
import dotty .tools .dotc .core .Symbols .*
22
24
import dotty .tools .dotc .core .Types .*
@@ -116,26 +118,69 @@ class PcInlayHintsProvider(
116
118
InlayHintKind .Type ,
117
119
)
118
120
.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 )
124
125
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 )
125
131
val startsWithBrace = text.lift(start).contains('{' )
126
132
val endsWithBrace = text.lift(end).contains('}' )
127
133
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 )
130
139
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
132
153
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)) =>
136
181
ih.add(
137
- adjusted .startPos.toLsp,
138
- List (LabelPart (" => " )),
182
+ pos .startPos.toLsp,
183
+ List (LabelPart (labelStr )),
139
184
InlayHintKind .Parameter
140
185
)
141
186
}
@@ -412,27 +457,55 @@ object InferredType:
412
457
413
458
end InferredType
414
459
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
419
486
420
- if (params.byNameParameters()){
487
+ if (params.namedParameters() || params. byNameParameters()) then
421
488
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
+ )
436
509
case _ => None
437
- } else None
438
- end ByNameParameters
510
+ else None
511
+ end Parameters
0 commit comments