Skip to content

Commit c8c598f

Browse files
committed
test symbol.defTree
1 parent 8e5ea1e commit c8c598f

File tree

10 files changed

+216
-0
lines changed

10 files changed

+216
-0
lines changed

compiler/src/dotty/tools/dotc/plugins/Plugin.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ sealed trait Plugin {
2828
*
2929
* Research plugin receives a phase plan and return a new phase plan, while
3030
* non-research plugin returns a list of phases to be inserted.
31+
*
32+
* @note Research plugins only compile with nightly build.
3133
*/
3234
def isResearch: Boolean = isInstanceOf[ResearchPlugin]
3335

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package hello
2+
3+
import lib._
4+
5+
class M(val n: Int) {
6+
val a = 30 * n
7+
class B(x: Int) {
8+
val b = x * a
9+
def bar(i: Int) = i * x
10+
}
11+
12+
def foo(i: Int) = i * n
13+
14+
def bar = {
15+
class C(val s: String)
16+
val c = new C("hello")
17+
def qux = c.s
18+
qux
19+
}
20+
}
21+
22+
23+
object Hello {
24+
def testLib: Unit = {
25+
val a = new A(30)
26+
val b = new a.B(24)
27+
a.foo(3)
28+
b.bar(9)
29+
}
30+
31+
def testHello: Unit = {
32+
val a = new M(30)
33+
val b = new a.B(24)
34+
a.foo(3)
35+
b.bar(9)
36+
}
37+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion
26+
)
27+
.dependsOn(lib)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion,
26+
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
27+
)
28+
.dependsOn(lib)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion,
26+
scalacOptions += "-Yretain-trees",
27+
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
28+
)
29+
.dependsOn(lib)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package lib
2+
3+
class A(val n: Int) {
4+
val a = 30 * n
5+
class B(x: Int) {
6+
val b = x * a
7+
def bar(i: Int) = i * x
8+
}
9+
10+
def foo(i: Int) = i * n
11+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package analyzer
2+
3+
import scala.language.implicitConversions
4+
5+
import dotty.tools.dotc._
6+
import core._
7+
import Contexts.Context
8+
import plugins._
9+
import Phases.Phase
10+
import ast.tpd
11+
import transform.MegaPhase.MiniPhase
12+
import Decorators._
13+
import Symbols.Symbol
14+
import Constants.Constant
15+
import transform.{Pickler, Staging}
16+
17+
class InitChecker extends PluginPhase with StandardPlugin {
18+
import tpd._
19+
20+
val name: String = "initChecker"
21+
override val description: String = "checks that under -Yretain-trees we may get tree for all symbols"
22+
23+
val phaseName = name
24+
25+
override val runsAfter = Set(Staging.name)
26+
override val runsBefore = Set(Pickler.name)
27+
28+
def init(options: List[String]): List[PluginPhase] = this :: Nil
29+
30+
private def checkDef(tree: Tree)(implicit ctx: Context): Tree = {
31+
val span = tree.symbol.defTree.span
32+
if (!(span.exists && span.end > span.start))
33+
ctx.error("cannot get tree for " + tree.symbol.show, tree.sourcePos)
34+
tree
35+
}
36+
37+
private def checkRef(tree: Tree)(implicit ctx: Context): Tree = {
38+
val helloPkgSym = ctx.requiredPackage("hello")
39+
val libPkgSym = ctx.requiredPackage("lib")
40+
val enclosingPkg = tree.symbol.enclosingPackageClass
41+
42+
if (enclosingPkg == helloPkgSym) { // source code
43+
checkDef(tree)
44+
}
45+
else if (enclosingPkg == libPkgSym) { // tasty from library
46+
checkDef(tree)
47+
// check that all sub-definitions have trees set properly
48+
transformAllDeep(tree.symbol.defTree)
49+
}
50+
51+
tree
52+
}
53+
54+
override def transformValDef(tree: ValDef)(implicit ctx: Context): Tree = checkDef(tree)
55+
56+
override def transformDefDef(tree: DefDef)(implicit ctx: Context): Tree = checkDef(tree)
57+
58+
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context): Tree = checkDef(tree)
59+
60+
override def transformSelect(tree: Select)(implicit ctx: Context): Tree = checkRef(tree)
61+
62+
override def transformIdent(tree: Ident)(implicit ctx: Context): Tree = checkRef(tree)
63+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pluginClass=analyzer.InitChecker
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version"))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Should compile OK without the plugin
2+
> app/compile
3+
4+
# Publish plugin locally
5+
> plugin/publishLocal
6+
7+
# Should NOT compile with just the plugin
8+
$ copy-file changes/plugin.sbt build.sbt
9+
> reload
10+
> clean
11+
-> app/compile
12+
13+
# Should compile with the plugin and -Yretain-trees
14+
$ copy-file changes/retain.sbt build.sbt
15+
> reload
16+
> clean
17+
> app/compile

0 commit comments

Comments
 (0)