Skip to content

Commit 1716bcd

Browse files
authored
Use comma counting for all signature help types (#19520)
Fixes scalameta/metals#6040
1 parent 453658b commit 1716bcd

File tree

2 files changed

+158
-19
lines changed

2 files changed

+158
-19
lines changed

Diff for: compiler/src/dotty/tools/dotc/util/Signatures.scala

+32-19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dotty.tools.dotc
22
package util
33

44
import dotty.tools.dotc.ast.NavigateAST
5+
import dotty.tools.dotc.ast.Positioned
56
import dotty.tools.dotc.ast.untpd
67
import dotty.tools.dotc.core.NameOps.*
78
import dotty.tools.dotc.core.StdNames.nme
@@ -99,7 +100,7 @@ object Signatures {
99100
findEnclosingApply(path, span) match
100101
case Apply(fun, params) => applyCallInfo(span, params, fun, false)
101102
case UnApply(fun, _, patterns) => unapplyCallInfo(span, fun, patterns)
102-
case appliedTypeTree @ AppliedTypeTree(_, types) => appliedTypeTreeCallInfo(appliedTypeTree, types)
103+
case appliedTypeTree @ AppliedTypeTree(_, types) => appliedTypeTreeCallInfo(span, appliedTypeTree, types)
103104
case tp @ TypeApply(fun, types) => applyCallInfo(span, types, fun, isTypeApply = true)
104105
case _ => (0, 0, Nil)
105106

@@ -154,13 +155,14 @@ object Signatures {
154155
* @param fun Function tree which is being applied
155156
*/
156157
private def appliedTypeTreeCallInfo(
158+
span: Span,
157159
fun: tpd.Tree,
158160
types: List[tpd.Tree]
159161
)(using Context): (Int, Int, List[Signature]) =
160162
val typeName = fun.symbol.name.show
161163
val typeParams = fun.symbol.typeRef.typeParams.map(_.paramName.show).map(TypeParam.apply(_))
162164
val denot = fun.denot.asSingleDenotation
163-
val activeParameter = (types.length - 1) max 0
165+
val activeParameter = findCurrentParamIndex(types, span, typeParams.length - 1)
164166

165167
val signature = Signature(typeName, List(typeParams), Some(typeName) , None, Some(denot))
166168
(activeParameter, 0, List(signature))
@@ -237,21 +239,8 @@ object Signatures {
237239
case _ :: untpd.TypeApply(_, args) :: _ => args
238240
case _ => Nil
239241

240-
val currentParamsIndex = (untpdArgs.indexWhere(_.span.contains(span)) match
241-
case -1 if untpdArgs.isEmpty => 0
242-
case -1 =>
243-
commaIndex(untpdArgs, span) match
244-
// comma is before CURSOR, so we are in parameter b example: test("a", CURSOR)
245-
case Some(index) if index <= span.end => untpdArgs.takeWhile(_.span.end < span.start).length
246-
// comma is after CURSOR, so we are in parameter a example: test("a" CURSOR,)
247-
case Some(index) => untpdArgs.takeWhile(_.span.start < span.end).length - 1
248-
// we are either in first or last parameter
249-
case None =>
250-
if untpdArgs.head.span.start >= span.end then 0
251-
else untpdArgs.length - 1 max 0
252-
253-
case n => n
254-
) min (alternativeSymbol.paramSymss(safeParamssListIndex).length - 1)
242+
val currentParamsIndex =
243+
findCurrentParamIndex(untpdArgs, span, alternativeSymbol.paramSymss(safeParamssListIndex).length - 1)
255244

256245
val pre = treeQualifier(fun)
257246
val alternativesWithTypes = alternatives.map(_.asSeenFrom(pre.tpe.widenTermRefExpr))
@@ -263,13 +252,37 @@ object Signatures {
263252
else
264253
(0, 0, Nil)
265254

255+
/** Finds current parameter index
256+
* @param args List of currently applied arguments
257+
* @param span The position of the cursor
258+
* @param maxIndex The maximum index of the parameter in the current apply list
259+
*
260+
* @return Index of the current parameter
261+
*/
262+
private def findCurrentParamIndex(args: List[Positioned], span: Span, maxIndex: Int)(using Context): Int =
263+
(args.indexWhere(_.span.contains(span)) match
264+
case -1 if args.isEmpty => 0
265+
case -1 =>
266+
commaIndex(args, span) match
267+
// comma is before CURSOR, so we are in parameter b example: test("a", CURSOR)
268+
case Some(index) if index <= span.end => args.takeWhile(_.span.end < span.start).length
269+
// comma is after CURSOR, so we are in parameter a example: test("a" CURSOR,)
270+
case Some(index) => args.takeWhile(_.span.start < span.end).length - 1
271+
// we are either in first or last parameter
272+
case None =>
273+
if args.head.span.start >= span.end then 0
274+
else args.length - 1 max 0
275+
276+
case n => n
277+
) min maxIndex
278+
266279
/** Parser ignores chars between arguments, we have to manually find the index of comma
267280
* @param untpdArgs List of applied untyped arguments
268281
* @param span The position of the cursor
269282
*
270283
* @return None if we are in first or last parameter, comma index otherwise
271284
*/
272-
private def commaIndex(untpdArgs: List[untpd.Tree], span: Span)(using Context): Option[Int] =
285+
private def commaIndex(untpdArgs: List[Positioned], span: Span)(using Context): Option[Int] =
273286
val previousArgIndex = untpdArgs.lastIndexWhere(_.span.end < span.end)
274287
for
275288
previousArg <- untpdArgs.lift(previousArgIndex)
@@ -301,7 +314,7 @@ object Signatures {
301314
val paramTypes = extractParamTypess(resultType, denot, patterns.size).flatten.map(stripAllAnnots)
302315
val paramNames = extractParamNamess(resultType, denot).flatten
303316

304-
val activeParameter = patterns.takeWhile(_.span.end < span.start).length min (paramTypes.length - 1)
317+
val activeParameter = findCurrentParamIndex(patterns, span, paramTypes.length - 1)
305318
val unapplySignature = toUnapplySignature(denot.asSingleDenotation, paramNames, paramTypes).toList
306319

307320
(activeParameter, 0, unapplySignature)

Diff for: presentation-compiler/test/dotty/tools/pc/tests/signaturehelp/SignatureHelpSuite.scala

+126
Original file line numberDiff line numberDiff line change
@@ -1373,3 +1373,129 @@ class SignatureHelpSuite extends BaseSignatureHelpSuite:
13731373
| test(@@""".stripMargin,
13741374
""
13751375
)
1376+
1377+
@Test def `type-var-position` =
1378+
check(
1379+
"""|trait Test[A, B]:
1380+
| def doThing[C](f: B => Test[A@@, C]) = ???
1381+
|""".stripMargin,
1382+
"""|Test[A, B]: Test
1383+
| ^
1384+
|""".stripMargin
1385+
)
1386+
1387+
@Test def `type-var-position-1` =
1388+
check(
1389+
"""|trait Test[A, B]:
1390+
| def doThing[C](f: B => Test[@@A, C]) = ???
1391+
|""".stripMargin,
1392+
"""|Test[A, B]: Test
1393+
| ^
1394+
|""".stripMargin
1395+
)
1396+
1397+
@Test def `type-var-position-2` =
1398+
check(
1399+
"""|trait Test[A, B]:
1400+
| def doThing[C](f: B => Test[A@@
1401+
| , C]) = ???
1402+
|""".stripMargin,
1403+
"""|Test[A, B]: Test
1404+
| ^
1405+
|""".stripMargin
1406+
)
1407+
1408+
@Test def `type-var-position-3` =
1409+
check(
1410+
"""|trait Test[A, B]:
1411+
| def doThing[C](f: B => Test[A, C@@]) = ???
1412+
|""".stripMargin,
1413+
"""|Test[A, B]: Test
1414+
| ^
1415+
|""".stripMargin
1416+
)
1417+
1418+
@Test def `type-var-position-4` =
1419+
check(
1420+
"""|trait Test[A, B]:
1421+
| def doThing[C](f: B => Test[A,@@ C]) = ???
1422+
|""".stripMargin,
1423+
"""|Test[A, B]: Test
1424+
| ^
1425+
|""".stripMargin
1426+
)
1427+
1428+
@Test def `type-var-position-5` =
1429+
check(
1430+
"""|trait Test[A, B]:
1431+
| def doThing[C](f: B => Test[A, @@C]) = ???
1432+
|""".stripMargin,
1433+
"""|Test[A, B]: Test
1434+
| ^
1435+
|""".stripMargin
1436+
)
1437+
1438+
@Test def `type-var-position-6` =
1439+
check(
1440+
"""|trait Test[A, B]:
1441+
| def doThing[C](f: B => Test[
1442+
| A@@,
1443+
| C
1444+
| ]) = ???
1445+
|""".stripMargin,
1446+
"""|Test[A, B]: Test
1447+
| ^
1448+
|""".stripMargin
1449+
)
1450+
1451+
@Test def `type-var-position-7` =
1452+
check(
1453+
"""|trait Test[A, B]:
1454+
| def doThing[C](f: B => Test[
1455+
| A,
1456+
| C@@
1457+
| ]) = ???
1458+
|""".stripMargin,
1459+
"""|Test[A, B]: Test
1460+
| ^
1461+
|""".stripMargin
1462+
)
1463+
1464+
@Test def `type-var-position-8` =
1465+
check(
1466+
"""|trait Test[A, B]:
1467+
| def doThing[C](f: B => Test[
1468+
| A,
1469+
| @@C
1470+
| ]) = ???
1471+
|""".stripMargin,
1472+
"""|Test[A, B]: Test
1473+
| ^
1474+
|""".stripMargin
1475+
)
1476+
1477+
@Test def `type-var-position-9` =
1478+
check(
1479+
"""|trait Test[A, B]:
1480+
| def doThing[C](f: B => Test[
1481+
| A,
1482+
| C
1483+
| @@]) = ???
1484+
|""".stripMargin,
1485+
"""|Test[A, B]: Test
1486+
| ^
1487+
|""".stripMargin
1488+
)
1489+
1490+
@Test def `type-var-position-10` =
1491+
check(
1492+
"""|trait Test[A, B]:
1493+
| def doThing[C](f: B => Test[@@
1494+
| A,
1495+
| C
1496+
| ]) = ???
1497+
|""".stripMargin,
1498+
"""|Test[A, B]: Test
1499+
| ^
1500+
|""".stripMargin
1501+
)

0 commit comments

Comments
 (0)