diff --git a/presentation-compiler/src/main/dotty/tools/pc/SelectionRangeProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/SelectionRangeProvider.scala index a7d07b12f40c..9dce37028bea 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/SelectionRangeProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/SelectionRangeProvider.scala @@ -6,10 +6,12 @@ import java.util as ju import scala.jdk.CollectionConverters._ import scala.meta.pc.OffsetParams +import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.interactive.Interactive import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.util.SourceFile +import dotty.tools.dotc.util.SourcePosition import dotty.tools.pc.utils.MtagsEnrichments.* import org.eclipse.lsp4j @@ -46,11 +48,7 @@ class SelectionRangeProvider( Interactive.pathTo(driver.openedTrees(uri), pos)(using ctx) val bareRanges = path - .map { tree => - val selectionRange = new SelectionRange() - selectionRange.setRange(tree.sourcePos.toLsp) - selectionRange - } + .flatMap(selectionRangesFromTree(pos)) val comments = driver.compilationUnits.get(uri).map(_.comments).toList.flatten @@ -79,6 +77,33 @@ class SelectionRangeProvider( } end selectionRange + /** Given a tree, create a seq of [[SelectionRange]]s corresponding to that tree. */ + private def selectionRangesFromTree(pos: SourcePosition)(tree: tpd.Tree)(using Context) = + def toSelectionRange(srcPos: SourcePosition) = + val selectionRange = new SelectionRange() + selectionRange.setRange(srcPos.toLsp) + selectionRange + + val treeSelectionRange = toSelectionRange(tree.sourcePos) + + tree match + case tpd.DefDef(name, paramss, tpt, rhs) => + // If source position is within a parameter list, add a selection range covering that whole list. + val selectedParams = + paramss + .iterator + .flatMap: // parameter list to a sourcePosition covering the whole list + case Seq(param) => Some(param.sourcePos) + case params @ Seq(head, tail*) => + val srcPos = head.sourcePos + val lastSpan = tail.last.span + Some(SourcePosition(srcPos.source, srcPos.span union lastSpan, srcPos.outer)) + case Seq() => None + .find(_.contains(pos)) + .map(toSelectionRange) + selectedParams ++ Seq(treeSelectionRange) + case _ => Seq(treeSelectionRange) + private def setParent( child: SelectionRange, parent: SelectionRange diff --git a/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala index 84417bb5e414..e277a67c466b 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala @@ -101,3 +101,49 @@ class SelectionRangeSuite extends BaseSelectionRangeSuite: |}<>region>>a: Int<>region>>a: Int, b: Int<>region>>def func(a: Int, b: Int) = + | a + b< + | a + b + |}""".stripMargin, + List[String]( + """|object Main extends App { + | val func = (>>region>>a: Int< + | a + b + |}""".stripMargin, + """|object Main extends App { + | val func = (>>region>>a: Int, b: Int< + | a + b + |}""".stripMargin, + """|object Main extends App { + | val func = >>region>>(a: Int, b: Int) => + | a + b<>region>>val func = (a: Int, b: Int) => + | a + b<