Skip to content

Commit

Permalink
refactor: undo changes in PcCollector
Browse files Browse the repository at this point in the history
  • Loading branch information
jkciesluk committed Oct 24, 2023
1 parent 6cca06c commit 31e5af9
Show file tree
Hide file tree
Showing 25 changed files with 342 additions and 492 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ case class DecorationOptions(
)

object DecorationOptions {
def apply(range: Range, text: String) =
def apply(text: String, range: Range) =
new DecorationOptions(
range,
renderOptions = ThemableDecorationInstanceRenderOptions(
Expand Down
23 changes: 17 additions & 6 deletions metals/src/main/scala/scala/meta/internal/metals/Compilers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -594,12 +594,23 @@ class Compilers(
compiler
.syntheticDecorations(pcParams)
.asScala
.map(_.map { decoration =>
DecorationOptions(
adjust.adjustRange(decoration.range()),
decoration.label(),
)
})
.map { decorations =>
val decorationOptions = decorations.map { decoration =>
DecorationOptions(
decoration.label(),
adjust.adjustRange(decoration.range()),
)
}
val isScala2 = compiler.scalaVersion().startsWith("2.")
if (
isScala2 && path.isWorksheet && !decorationOptions.isEmpty()
) {
// In scala 2 worksheet, last decoration is for synthetic `main` method
decorationOptions.remove(decorationOptions.size() - 1)
decorationOptions
} else decorationOptions
}

}
.getOrElse(Future.successful(Nil.asJava))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,14 @@ class MetalsLspService(
for {
_ <- buildServerPromise.future
_ <- focusedDocument()
.map(publishSynthetics)
.map { path =>
Future.sequence(
List(
publishSynthetics(path),
worksheetProvider.onDidFocus(path),
)
)
}
.getOrElse(Future.successful(()))
} yield ()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,24 @@ trait MtagsEnrichments extends ScalametaCommonEnrichments {

def encloses(other: RangeParams): Boolean =
pos.start <= other.offset() && pos.end >= other.endOffset()

def adjust(
text: Array[Char],
forRename: Boolean = false
): (Position, Boolean) = {
val isBackticked = text(pos.start) == '`' &&
text(pos.end - 1) == '`' &&
pos.start != (pos.end - 1) // for one character names, e.g. `c`
// start-^^-end
val isOldNameBackticked = text(pos.start) == '`' &&
(text(pos.end - 1) != '`' || pos.start == (pos.end - 1)) &&
text(pos.end + 1) == '`'
if (isBackticked && forRename)
(pos.withStart(pos.start + 1).withEnd(pos.end - 1), true)
else if (isOldNameBackticked) // pos
(pos.withEnd(pos.end + 2), false)
else (pos, false)
}
}

implicit class XtensionRangeParameters(pos: RangeParams) {
Expand Down
13 changes: 13 additions & 0 deletions mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,19 @@ class MetalsGlobal(
}
}

private val forCompMethods =
Set(nme.map, nme.flatMap, nme.withFilter, nme.foreach)

// We don't want to collect synthethic `map`, `withFilter`, `foreach` and `flatMap` in for-comprenhensions
def isForComprehensionMethod(sel: Select): Boolean = {
val syntheticName = sel.name match {
case name: TermName => forCompMethods(name)
case _ => false
}
val wrongSpan = sel.qualifier.pos.includes(sel.namePosition.focusStart)
syntheticName && wrongSpan
}

// Extractor for both term and type applications like `foo(1)` and foo[T]`
object TreeApply {
def unapply(tree: Tree): Option[(Tree, List[Tree])] =
Expand Down
143 changes: 26 additions & 117 deletions mtags/src/main/scala-2/scala/meta/internal/pc/PcCollector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package scala.meta.internal.pc
import scala.reflect.internal.util.RangePosition

import scala.meta.pc.OffsetParams
import scala.meta.pc.RangeParams
import scala.meta.pc.VirtualFileParams

abstract class PcCollector[T](
Expand Down Expand Up @@ -67,24 +66,6 @@ abstract class PcCollector[T](
all.filter(s => s != NoSymbol && !s.isError)
}

def adjust(
pos: Position,
forRename: Boolean = false
): (Position, Boolean) = {
val isBackticked = text(pos.start) == '`' &&
text(pos.end - 1) == '`' &&
pos.start != (pos.end - 1) // for one character names, e.g. `c`
// start-^^-end
val isOldNameBackticked = text(pos.start) == '`' &&
(text(pos.end - 1) != '`' || pos.start == (pos.end - 1)) &&
text(pos.end + 1) == '`'
if (isBackticked && forRename)
(pos.withStart(pos.start + 1).withEnd(pos.end - 1), true)
else if (isOldNameBackticked) // pos
(pos.withEnd(pos.end + 2), false)
else (pos, false)
}

private lazy val namedArgCache = {
val parsedTree = parseTree(unit.source)
parsedTree.collect { case arg @ AssignOrNamedArg(_, rhs) =>
Expand Down Expand Up @@ -195,28 +176,10 @@ abstract class PcCollector[T](
None
}

def treesInRange(rangeParams: RangeParams): List[Tree] = {
val pos: Position =
unit.position(rangeParams.offset()).withEnd(rangeParams.endOffset())
val tree = locateTree(pos, unit.lastBody, false)
if (tree.isEmpty) {
List(unit.lastBody)
} else if (!tree.pos.isDefined || rangeParams.offset() <= tree.pos.start) {
List(tree)
} else {
tree.children
.filter(c =>
!c.pos.isDefined ||
c.pos.start <= rangeParams.endOffset && c.pos.end >= rangeParams
.offset()
)
}
}

def result(): List[T] = {
params match {
case _: OffsetParams => resultWithSought()
case _ => resultAllOccurences()(List(unit.lastBody))
case _ => resultAllOccurences().toList
}
}

Expand Down Expand Up @@ -274,37 +237,29 @@ abstract class PcCollector[T](
sought.exists(f)
}

traverseSought(soughtTreeFilter, soughtFilter)(List(unit.lastBody))
traverseSought(soughtTreeFilter, soughtFilter).toList

case None => Nil
}
}

def resultAllOccurences(includeSynthetics: Boolean = false)(
toTraverse: List[Tree] = List(unit.lastBody)
): List[T] = {
def resultAllOccurences(): Set[T] = {
def noTreeFilter = (_: Tree) => true
def noSoughtFilter = (_: (Symbol => Boolean)) => true

traverseSought(noTreeFilter, noSoughtFilter, includeSynthetics)(toTraverse)
traverseSought(noTreeFilter, noSoughtFilter)
}

def traverseSought(
filter: Tree => Boolean,
soughtFilter: (Symbol => Boolean) => Boolean,
includeSynthetics: Boolean = false
)(
toTraverse: List[Tree]
): List[T] = {
def syntheticFilter(tree: Tree) = includeSynthetics &&
tree.pos.isOffset &&
tree.symbol.isImplicit
soughtFilter: (Symbol => Boolean) => Boolean
): Set[T] = {
// Now find all matching symbols in the document, comments identify <<>> as the symbol we are looking for
def traverseWithParent(parent: Option[Tree])(
acc: List[T],
acc: Set[T],
tree: Tree
): List[T] = {
val traverse: (List[T], Tree) => List[T] = traverseWithParent(
): Set[T] = {
val traverse: (Set[T], Tree) => Set[T] = traverseWithParent(
Some(tree)
)
def collect(t: Tree, pos: Position, sym: Option[Symbol] = None): T =
Expand All @@ -315,13 +270,11 @@ abstract class PcCollector[T](
* All indentifiers such as:
* val a = <<b>>
*/
case ident: Ident
if ident.pos.isRange && filter(ident) ||
syntheticFilter(ident) =>
case ident: Ident if ident.pos.isRange && filter(ident) =>
if (ident.symbol == NoSymbol)
collect(ident, ident.pos, fallbackSymbol(ident.name, pos)) :: acc
acc + collect(ident, ident.pos, fallbackSymbol(ident.name, pos))
else
collect(ident, ident.pos) :: acc
acc + collect(ident, ident.pos)

/**
* Needed for type trees such as:
Expand All @@ -330,10 +283,10 @@ abstract class PcCollector[T](
case tpe: TypeTree
if tpe.pos.isRange && tpe.original != null && filter(tpe) =>
tpe.original.children.foldLeft(
collect(
acc + collect(
tpe.original,
typePos(tpe)
) :: acc
)
)(traverse(_, _))

/**
Expand All @@ -343,20 +296,11 @@ abstract class PcCollector[T](
case sel: Select if sel.pos.isRange && filter(sel) =>
val newAcc =
if (isForComprehensionMethod(sel)) acc
else collect(sel, sel.namePosition) :: acc
else acc + collect(sel, sel.namePosition)
traverse(
newAcc,
sel.qualifier
)

case sel: Select if syntheticFilter(sel) =>
traverse(
collect(
sel,
sel.pos
) :: acc,
sel.qualifier
)
/* all definitions:
* def <<foo>> = ???
* class <<Foo>> = ???
Expand All @@ -368,7 +312,7 @@ abstract class PcCollector[T](
df,
df.namePosition
)
if (acc.contains(t)) acc else t :: acc
if (acc(t)) acc else acc + t
})(traverse(_, _))
/* Named parameters, since they don't show up in typed tree:
* foo(<<name>> = "abc")
Expand Down Expand Up @@ -401,35 +345,18 @@ abstract class PcCollector[T](
*/
case bind: Bind if bind.pos.isDefined && filter(bind) =>
bind.children.foldLeft(
collect(
acc + collect(
bind,
bind.namePosition
) :: acc
)
)(traverse(_, _))

/**
* We don't want to collect type parameters in for-comp map, flatMap etc.
*/
case TypeApply(sel: Select, _) if isForComprehensionMethod(sel) =>
traverse(acc, sel.qualifier)

/**
* We don't automatically traverser types like:
* val opt: Option[<<String>>] =
*/
case tpe: TypeTree if tpe.original != null =>
tpe.original.children.foldLeft(acc)(traverse(_, _))

/**
* For collecting synthetic type parameters:
* def hello[T](t: T) = t
* val x = hello<<[List[Int]]>>(List<<Int>>(1))
*/
case tpe: TypeTree if includeSynthetics && tpe.pos.isOffset =>
collect(
tpe,
tpe.pos
) :: acc
/**
* Some type trees don't have symbols attached such as:
* type A = List[_ <: <<Iterable>>[Int]]
Expand All @@ -439,19 +366,13 @@ abstract class PcCollector[T](
soughtFilter(_.decodedName == id.name.decoded) =>
fallbackSymbol(id.name, id.pos) match {
case Some(sym) if soughtFilter(_ == sym) =>
collect(
acc + collect(
id,
id.pos
) :: acc
)
case _ => acc
}

/**
* We don't want to traverse type from synthetic match-case in
* val <<hd :: tail = List(1,2,3)>>
*/
case Typed(expr, tpt) if !tpt.pos.isRange =>
traverse(acc, expr)
/**
* For traversing annotations:
* @<<JsonNotification>>("")
Expand Down Expand Up @@ -495,10 +416,10 @@ abstract class PcCollector[T](
case name: NameTree
if soughtFilter(_ == name.symbol) && name.pos.isRange =>
tree.children.foldLeft(
collect(
acc + collect(
name,
name.namePosition
) :: acc
)
)(traverse(_, _))

// needed for `classOf[<<ABC>>]`
Expand All @@ -507,7 +428,7 @@ abstract class PcCollector[T](
val posStart = text.indexOfSlice(sym.decodedName, lit.pos.start)
if (posStart == -1) acc
else
collect(
acc + collect(
lit,
new RangePosition(
lit.pos.source,
Expand All @@ -516,13 +437,14 @@ abstract class PcCollector[T](
posStart + sym.decodedName.length
),
Option(sym)
) :: acc
)

case _ =>
tree.children.foldLeft(acc)(traverse(_, _))
}
}
toTraverse.flatMap(traverseWithParent(None)(List.empty[T], _))
val all = traverseWithParent(None)(Set.empty[T], unit.lastBody)
all
}

private def annotationChildren(mdef: MemberDef): List[Tree] = {
Expand All @@ -543,17 +465,4 @@ abstract class PcCollector[T](
}
}

private val forCompMethods =
Set(nme.map, nme.flatMap, nme.withFilter, nme.foreach)

// We don't want to collect synthethic `map`, `withFilter`, `foreach` and `flatMap` in for-comprenhensions
private def isForComprehensionMethod(sel: Select): Boolean = {
val syntheticName = sel.name match {
case name: TermName => forCompMethods(name)
case _ => false
}
val wrongSpan = sel.qualifier.pos.includes(sel.namePosition.focusStart)
syntheticName && wrongSpan
}

}
Loading

0 comments on commit 31e5af9

Please sign in to comment.