Skip to content

Commit

Permalink
TextDocumentOps: capture lambdas for SAM
Browse files Browse the repository at this point in the history
  • Loading branch information
kitbellew committed Jan 9, 2025
1 parent bbbeb62 commit d554051
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ trait VersionSpecificOps {
)) Some(None)
else None
}

// TODO: move the other specializations back to TextDocumentOps when 2.11 is retired
def getSyntheticSAMClass(gt: g.Function): Option[g.Symbol] = None

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ trait VersionSpecificOps {
.get[g.analyzer.NamedApplyInfo].map(Some(_))
}

def getSyntheticSAMClass(gt: g.Function): Option[g.Symbol] = gt.attachments
.get[global.SAMFunction].map(_.synthCls)

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ trait VersionSpecificOps {
.get[g.analyzer.NamedApplyInfo].map(Some(_))
}

def getSyntheticSAMClass(gt: g.Function): Option[g.Symbol] = gt.attachments
.get[global.SAMFunction].map(_.synthCls)

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ trait TextDocumentOps {
def toTextDocument(explicitDialect: Option[m.Dialect]): s.TextDocument = {
pointsCache.clear()
val occurrences = emptyOccurrenceMap()
val samoccurrences = emptyOccurrenceMap()
val symbols = mutable.Map[String, s.SymbolInformation]()
val synthetics = mutable.ListBuffer[s.Synthetic]()
// macro expandees can have cycles, keep tracks of visited nodes.
Expand All @@ -63,6 +64,7 @@ trait TextDocumentOps {
val mctordefs = mutable.Map[Int, m.Name]() // start offset of ctor -> ctor's anonymous name
val mctorrefs = mutable.Map[Int, m.Name]() // start offset of new/init -> new's anonymous name
val msupers = mutable.Map.empty[Int, m.Term.Super] // end offset
val mfuncs = mutable.Map.empty[Int, m.Position] // start offset of a function

// Occurrences for names in val patterns, like `val (a, b) =`. Unlike the `occurrences` map, val pattern
// occurrences uses "last occurrence wins" instead of "first occurrences wins" when disambiguating between
Expand All @@ -77,6 +79,29 @@ trait TextDocumentOps {
def addOccurrence(mpos: m.Position, gsym: g.Symbol, role: Role): Unit =
addOccurrenceFromSemantic(mpos, gsym.toSemantic, role)

def addSamOccurrence(gt: g.Function) = getSyntheticSAMClass(gt).foreach { sam =>
val gpos = gt.pos
val gsym = gt.symbol
def atPos(mpos: m.Position): Unit = gsym.toSemantic match {
case Symbols.None =>
case ssym =>
samoccurrences.update(mpos, (ssym, Role.DEFINITION))
if (!shouldNotSaveSymbol(gsym) && !shouldNotSaveSemanticSymbol(ssym)) {
saveSymbolDo(sam)
saveSymbolFromSemantic(gsym.setInfo(sam.tpe), ssym)
}
}
if (gpos.isDefined && (gsym ne null)) {
val gstart = gpos.start
mfuncs.get(gstart).fold {
mstarts.get(gstart).foreach { name =>
val mpos = name.pos
if (mpos.end == gpos.end) atPos(mpos)
}
}(atPos)
}
}

def addPatOccurrenceFromSemantic(mpos: m.Position, ssym: String): Unit =
if (ssym != Symbols.None) mpatoccurrences.update(mpos, (ssym, Role.DEFINITION))
def addPatOccurrence(mpos: m.Position, gsym: g.Symbol): Unit =
Expand Down Expand Up @@ -175,6 +200,8 @@ trait TextDocumentOps {
case mtree: m.Init => indexArgNames(mtree); mctorrefs(mtree.pos.start) = mtree.name
case _: m.Name.Anonymous | _: m.Name.Placeholder | _: m.Name.This =>
case mtree: m.Name => indexName(mtree)
case mtree @ (_: m.Term.FunctionTerm | _: m.Term.AnonymousFunction) =>
val mpos = mtree.pos; mfuncs.update(mpos.start, mpos)
case mtree: m.Tree.WithPats => mtree.pats match {
case (_: m.Pat.Var) :: Nil =>
case pats => indexPats(pats)
Expand Down Expand Up @@ -576,6 +603,7 @@ trait TextDocumentOps {
}

case t: g.Function =>
addSamOccurrence(t)
t.vparams.foreach { p =>
if (!(p.symbol.isSynthetic || p.name.decoded.startsWith("x$"))) traverse(p)
}
Expand Down Expand Up @@ -665,7 +693,7 @@ trait TextDocumentOps {
val finalOccurrences = {
val buf = List.newBuilder[s.SymbolOccurrence]
for {
map <- Iterator(occurrences, mpatoccurrences)
map <- Iterator(occurrences, mpatoccurrences, samoccurrences)
(pos, (sym, role)) <- map
flatSym <- sym.asMulti
} buf += s.SymbolOccurrence(Some(pos.toRange), flatSym, role)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class SingleAbstractMethod/*<=example.SingleAbstractMethod#*/ {
}
def withSAM/*<=example.SingleAbstractMethod#withSAM().*/(a/*<=example.SingleAbstractMethod#withSAM().(a)*/: SAM/*=>example.SingleAbstractMethod#SAM#*/) = a/*=>example.SingleAbstractMethod#withSAM().(a)*/.foo/*=>example.SingleAbstractMethod#SAM#foo().*/(0)

withSAM/*=>example.SingleAbstractMethod#withSAM().*/(_ +/*=>scala.Int#`+`(+4).*/ 1)
withSAM/*=>example.SingleAbstractMethod#withSAM().*/((x/*<=local0*/: Int/*=>scala.Int#*/) => x/*=>local0*/ -/*=>scala.Int#`-`(+3).*/ 1)
withSAM/*=>example.SingleAbstractMethod#withSAM().*/(_ + 1/*<=local0*/)
withSAM/*=>example.SingleAbstractMethod#withSAM().*/((x: Int) => x - 1/*<=local3*/)

def funcSAM/*<=example.SingleAbstractMethod#funcSAM().*/(y/*<=example.SingleAbstractMethod#funcSAM().(y)*/: Int/*=>scala.Int#*/) = y/*=>example.SingleAbstractMethod#funcSAM().(y)*/ */*=>scala.Int#`*`(+3).*/ 2
withSAM/*=>example.SingleAbstractMethod#withSAM().*/(funcSAM/*=>example.SingleAbstractMethod#funcSAM().*/)
withSAM/*=>example.SingleAbstractMethod#withSAM().*/(funcSAM/*=>example.SingleAbstractMethod#funcSAM().*//*<=local6*/)

}
24 changes: 18 additions & 6 deletions tests-semanticdb/src/test/resources/metac.expect_2.13
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ Schema => SemanticDB v4
Uri => semanticdb/integration/src/main/scala-2.13/example/SingleAbstractMethod.scala
Text => non-empty
Language => Scala
Symbols => 11 entries
Occurrences => 27 entries
Symbols => 15 entries
Occurrences => 30 entries

Symbols:
example/SingleAbstractMethod# => class SingleAbstractMethod extends AnyRef { +4 decls }
Expand All @@ -115,9 +115,18 @@ example/SingleAbstractMethod#withSAM(). => method withSAM(a: SAM): Int
Int => scala/Int#
example/SingleAbstractMethod#withSAM().(a) => param a: SAM
SAM => example/SingleAbstractMethod#SAM#
local0 => param x: Int
local0 => val local $anonfun: $anon
$anon => local1
local1 => class $anon extends Object with SAM { +1 decls }
Object => java/lang/Object#
SAM => example/SingleAbstractMethod#SAM#
local3 => val local $anonfun: $anon
$anon => local1
local5 => param x: Int
Int => scala/Int#
local1 => param y: Int
local6 => val local $anonfun: $anon
$anon => local1
local8 => param y: Int
Int => scala/Int#

Occurrences:
Expand All @@ -135,11 +144,13 @@ Occurrences:
[7:24..7:25): a => example/SingleAbstractMethod#withSAM().(a)
[7:26..7:29): foo => example/SingleAbstractMethod#SAM#foo().
[9:2..9:9): withSAM => example/SingleAbstractMethod#withSAM().
[9:10..9:15): _ + 1 <= local0
[9:12..9:13): + => scala/Int#`+`(+4).
[10:2..10:9): withSAM => example/SingleAbstractMethod#withSAM().
[10:11..10:12): x <= local0
[10:10..10:27): (x: Int) => x - 1 <= local3
[10:11..10:12): x <= local5
[10:14..10:17): Int => scala/Int#
[10:22..10:23): x => local0
[10:22..10:23): x => local5
[10:24..10:25): - => scala/Int#`-`(+3).
[12:6..12:13): funcSAM <= example/SingleAbstractMethod#funcSAM().
[12:14..12:15): y <= example/SingleAbstractMethod#funcSAM().(y)
Expand All @@ -148,6 +159,7 @@ Occurrences:
[12:26..12:27): * => scala/Int#`*`(+3).
[13:2..13:9): withSAM => example/SingleAbstractMethod#withSAM().
[13:10..13:17): funcSAM => example/SingleAbstractMethod#funcSAM().
[13:10..13:17): funcSAM <= local6

semanticdb/integration/src/main/scala/example/Access.scala
----------------------------------------------------------
Expand Down

0 comments on commit d554051

Please sign in to comment.