Skip to content

Commit ce30677

Browse files
committed
record end markers in trees and semanticdb
1 parent d2dd083 commit ce30677

File tree

6 files changed

+239
-6
lines changed

6 files changed

+239
-6
lines changed

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,40 @@ object Trees {
327327

328328
extension (mdef: untpd.DefTree) def mods: untpd.Modifiers = mdef.rawMods
329329

330-
abstract class NamedDefTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] {
330+
/** PackageDef | NamedDefTree */
331+
sealed trait WithEndMarker:
332+
self: Attachment.Container =>
333+
334+
import WithEndMarker.*
335+
336+
final def endToken: SimpleName = endMarker.stripModuleClassSuffix.lastPart
337+
338+
protected def endMarker: Name
339+
340+
def setEndSpan(span: Span): self.type =
341+
self.putAttachment(EndMarker, (span, endToken))
342+
this
343+
344+
def endSpan: Option[Span] = self.getAttachment(EndMarker).collect {
345+
// var setter copies the end marker, but the tree will have a different name,
346+
// so check that the end marker has not been renamed
347+
case (span, token) if token eq endToken => span
348+
}
349+
350+
object WithEndMarker:
351+
/** Property key for trees with an `end` marker */
352+
private val EndMarker: Property.StickyKey[(Span, SimpleName)] = Property.StickyKey()
353+
354+
end WithEndMarker
355+
356+
abstract class NamedDefTree[-T >: Untyped](implicit @constructorOnly src: SourceFile)
357+
extends NameTree[T] with DefTree[T] with WithEndMarker {
331358
type ThisTree[-T >: Untyped] <: NamedDefTree[T]
332359

360+
protected def endMarker =
361+
if name == nme.CONSTRUCTOR then nme.this_
362+
else name
363+
333364
/** The position of the name defined by this definition.
334365
* This is a point position if the definition is synthetic, or a range position
335366
* if the definition comes from source.
@@ -857,9 +888,10 @@ object Trees {
857888

858889
/** package pid { stats } */
859890
case class PackageDef[-T >: Untyped] private[ast] (pid: RefTree[T], stats: List[Tree[T]])(implicit @constructorOnly src: SourceFile)
860-
extends ProxyTree[T] {
891+
extends ProxyTree[T] with WithEndMarker {
861892
type ThisTree[-T >: Untyped] = PackageDef[T]
862893
def forwardTo: RefTree[T] = pid
894+
protected def endMarker: Name = pid.name
863895
}
864896

865897
/** arg @annot */

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,8 +1283,8 @@ object Parsers {
12831283
in.token == IDENTIFIER && in.name == nme.extension
12841284
case PackageDef(pid: RefTree, _) =>
12851285
in.isIdent && in.name == pid.name
1286-
case PatDef(_, IdPattern(id, _) :: Nil, _, _) =>
1287-
in.isIdent && in.name == id.name
1286+
case PatDef(_, IdPattern(id, _) :: Nil, _, _) => // TODO: it looks like this case is never reached
1287+
in.isIdent && in.name == id.name
12881288
case stat: MemberDef if stat.mods.is(Given) => in.token == GIVEN
12891289
case _: PatDef => in.token == VAL
12901290
case _: If => in.token == IF
@@ -1295,9 +1295,21 @@ object Parsers {
12951295
case _: (ForYield | ForDo) => in.token == FOR
12961296
case _ => false
12971297

1298+
def matchesWithUpdated(stat: Tree): Boolean = {
1299+
val didMatch = matches(stat)
1300+
if didMatch then
1301+
stat match
1302+
case stat: WithEndMarker =>
1303+
val end = in.lastCharOffset
1304+
stat.setEndSpan(Span(end - stat.endToken.length, end))
1305+
case _ =>
1306+
()
1307+
didMatch
1308+
}
1309+
12981310
if in.token == END then
12991311
val start = in.skipToken()
1300-
if stats.isEmpty || !matches(stats.last) then
1312+
if stats.isEmpty || !matchesWithUpdated(stats.last) then
13011313
syntaxError("misaligned end marker", Span(start, in.lastCharOffset))
13021314
in.token = IDENTIFIER // Leaving it as the original token can confuse newline insertion
13031315
in.nextToken()

compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core._
66
import Phases._
77
import ast.tpd._
88
import ast.untpd.given
9-
import ast.Trees.mods
9+
import ast.Trees.{mods, WithEndMarker}
1010
import Contexts._
1111
import Symbols._
1212
import Flags._
@@ -240,6 +240,12 @@ class ExtractSemanticDB extends Phase:
240240
case _ =>
241241
traverseChildren(tree)
242242

243+
tree match
244+
case tree: WithEndMarker =>
245+
for endSpan <- tree.endSpan do
246+
registerUseGuarded(None, tree.symbol, endSpan, tree.source)
247+
case _ =>
248+
243249
end traverse
244250

245251
private def funParamSymbol(funSym: Symbol)(using Context): Name => String =
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package endmarkers:
2+
3+
class MultiCtor/*<-endmarkers::MultiCtor#*/(val i/*<-endmarkers::MultiCtor#i.*/: Int/*->scala::Int#*/):
4+
def this()/*<-endmarkers::MultiCtor#`<init>`(+1).*/ =
5+
this(23)
6+
end this/*->endmarkers::MultiCtor#`<init>`(+1).*/
7+
end MultiCtor/*->endmarkers::MultiCtor#*/
8+
9+
/*<-endmarkers::EndMarkers$package.*/def topLevelMethod/*<-endmarkers::EndMarkers$package.topLevelMethod().*/: String/*->scala::Predef.String#*/ =
10+
"hello"
11+
end topLevelMethod/*->endmarkers::EndMarkers$package.topLevelMethod().*/
12+
13+
val topLevelVal/*<-endmarkers::EndMarkers$package.topLevelVal.*/: Int/*->scala::Int#*/ =
14+
23
15+
end topLevelVal/*->endmarkers::EndMarkers$package.topLevelVal.*/
16+
17+
var topLevelVar/*<-endmarkers::EndMarkers$package.topLevelVar().*/: String/*->scala::Predef.String#*/ =
18+
""
19+
end topLevelVar/*->endmarkers::EndMarkers$package.topLevelVar().*/
20+
21+
class Container/*<-endmarkers::Container#*/:
22+
23+
def foo/*<-endmarkers::Container#foo().*/ =
24+
(/*->scala::Tuple3.apply().*/1,2,3)
25+
end foo/*->endmarkers::Container#foo().*/
26+
27+
val bar/*<-endmarkers::Container#bar.*/ =
28+
(/*->scala::Tuple3.apply().*/4,5,6)
29+
end bar/*->endmarkers::Container#bar.*/
30+
31+
var baz/*<-endmarkers::Container#baz().*/ =
32+
15
33+
end baz/*->endmarkers::Container#baz().*/
34+
35+
end Container/*->endmarkers::Container#*/
36+
37+
def topLevelWithLocals/*<-endmarkers::EndMarkers$package.topLevelWithLocals().*/: Unit/*->scala::Unit#*/ =
38+
39+
val localVal/*<-local0*/ =
40+
37
41+
end localVal/*->local0*/
42+
43+
var localVar/*<-local1*/ =
44+
43
45+
end localVar/*->local1*/
46+
47+
def localDef/*<-local2*/ =
48+
97
49+
end localDef/*->local2*/
50+
51+
end topLevelWithLocals/*->endmarkers::EndMarkers$package.topLevelWithLocals().*/
52+
53+
end endmarkers
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package endmarkers:
2+
3+
class MultiCtor(val i: Int):
4+
def this() =
5+
this(23)
6+
end this
7+
end MultiCtor
8+
9+
def topLevelMethod: String =
10+
"hello"
11+
end topLevelMethod
12+
13+
val topLevelVal: Int =
14+
23
15+
end topLevelVal
16+
17+
var topLevelVar: String =
18+
""
19+
end topLevelVar
20+
21+
class Container:
22+
23+
def foo =
24+
(1,2,3)
25+
end foo
26+
27+
val bar =
28+
(4,5,6)
29+
end bar
30+
31+
var baz =
32+
15
33+
end baz
34+
35+
end Container
36+
37+
def topLevelWithLocals: Unit =
38+
39+
val localVal =
40+
37
41+
end localVal
42+
43+
var localVar =
44+
43
45+
end localVar
46+
47+
def localDef =
48+
97
49+
end localDef
50+
51+
end topLevelWithLocals
52+
53+
end endmarkers

tests/semanticdb/metac.expect

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,83 @@ Occurrences:
658658
[0:8..0:15): example <- example/
659659
[2:7..2:18): EmptyObject <- example/EmptyObject.
660660

661+
expect/EndMarkers.scala
662+
-----------------------
663+
664+
Summary:
665+
Schema => SemanticDB v4
666+
Uri => EndMarkers.scala
667+
Text => empty
668+
Language => Scala
669+
Symbols => 22 entries
670+
Occurrences => 40 entries
671+
672+
Symbols:
673+
endmarkers/Container# => class Container
674+
endmarkers/Container#`<init>`(). => primary ctor <init>
675+
endmarkers/Container#`baz_=`(). => var method baz_=
676+
endmarkers/Container#`baz_=`().(x$1) => param x$1
677+
endmarkers/Container#bar. => val method bar
678+
endmarkers/Container#baz(). => var method baz
679+
endmarkers/Container#foo(). => method foo
680+
endmarkers/EndMarkers$package. => final package object endmarkers
681+
endmarkers/EndMarkers$package.`topLevelVar_=`(). => var method topLevelVar_=
682+
endmarkers/EndMarkers$package.`topLevelVar_=`().(x$1) => param x$1
683+
endmarkers/EndMarkers$package.topLevelMethod(). => method topLevelMethod
684+
endmarkers/EndMarkers$package.topLevelVal. => val method topLevelVal
685+
endmarkers/EndMarkers$package.topLevelVar(). => var method topLevelVar
686+
endmarkers/EndMarkers$package.topLevelWithLocals(). => method topLevelWithLocals
687+
endmarkers/MultiCtor# => class MultiCtor
688+
endmarkers/MultiCtor#`<init>`(). => primary ctor <init>
689+
endmarkers/MultiCtor#`<init>`().(i) => val param i
690+
endmarkers/MultiCtor#`<init>`(+1). => ctor <init>
691+
endmarkers/MultiCtor#i. => val method i
692+
local0 => val local localVal
693+
local1 => var local localVar
694+
local2 => local localDef
695+
696+
Occurrences:
697+
[0:8..0:18): endmarkers <- endmarkers/
698+
[2:8..2:17): MultiCtor <- endmarkers/MultiCtor#
699+
[2:17..2:17): <- endmarkers/MultiCtor#`<init>`().
700+
[2:22..2:23): i <- endmarkers/MultiCtor#i.
701+
[2:25..2:28): Int -> scala/Int#
702+
[3:8..3:14): <- endmarkers/MultiCtor#`<init>`(+1).
703+
[4:11..4:11): -> endmarkers/MultiCtor#`<init>`().
704+
[5:8..5:12): this -> endmarkers/MultiCtor#`<init>`(+1).
705+
[6:6..6:15): MultiCtor -> endmarkers/MultiCtor#
706+
[8:2..8:2): <- endmarkers/EndMarkers$package.
707+
[8:6..8:20): topLevelMethod <- endmarkers/EndMarkers$package.topLevelMethod().
708+
[8:22..8:28): String -> scala/Predef.String#
709+
[10:6..10:20): topLevelMethod -> endmarkers/EndMarkers$package.topLevelMethod().
710+
[12:6..12:17): topLevelVal <- endmarkers/EndMarkers$package.topLevelVal.
711+
[12:19..12:22): Int -> scala/Int#
712+
[14:6..14:17): topLevelVal -> endmarkers/EndMarkers$package.topLevelVal.
713+
[16:6..16:17): topLevelVar <- endmarkers/EndMarkers$package.topLevelVar().
714+
[16:19..16:25): String -> scala/Predef.String#
715+
[18:6..18:17): topLevelVar -> endmarkers/EndMarkers$package.topLevelVar().
716+
[20:8..20:17): Container <- endmarkers/Container#
717+
[22:4..22:4): <- endmarkers/Container#`<init>`().
718+
[22:8..22:11): foo <- endmarkers/Container#foo().
719+
[23:7..23:7): -> scala/Tuple3.apply().
720+
[24:8..24:11): foo -> endmarkers/Container#foo().
721+
[26:8..26:11): bar <- endmarkers/Container#bar.
722+
[27:7..27:7): -> scala/Tuple3.apply().
723+
[28:8..28:11): bar -> endmarkers/Container#bar.
724+
[30:8..30:11): baz <- endmarkers/Container#baz().
725+
[32:8..32:11): baz -> endmarkers/Container#baz().
726+
[34:6..34:15): Container -> endmarkers/Container#
727+
[36:6..36:24): topLevelWithLocals <- endmarkers/EndMarkers$package.topLevelWithLocals().
728+
[36:26..36:30): Unit -> scala/Unit#
729+
[38:8..38:16): localVal <- local0
730+
[40:8..40:16): localVal -> local0
731+
[42:8..42:16): localVar <- local1
732+
[44:8..44:16): localVar -> local1
733+
[46:8..46:16): localDef <- local2
734+
[48:8..48:16): localDef -> local2
735+
[50:6..50:24): topLevelWithLocals -> endmarkers/EndMarkers$package.topLevelWithLocals().
736+
[52:4..52:14): endmarkers -> endmarkers/
737+
661738
expect/EnumVal.scala
662739
--------------------
663740

0 commit comments

Comments
 (0)