Skip to content

Commit 4a5314d

Browse files
committed
Remove the makefile and refactored the testsuite
- the testsuite now builds a map sourcefile -> tastyfile, thus allowing a test to possess several class in the same source code
1 parent eeb6df7 commit 4a5314d

File tree

7 files changed

+156
-58
lines changed

7 files changed

+156
-58
lines changed

library/src/scala/tasty/reflect/TreeUtils.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ trait TreeUtils
104104
case TypeTree.Block(typedefs, tpt) => foldTypeTree(foldTrees(x, typedefs), tpt)
105105
case TypeTree.MatchType(boundopt, selector, cases) =>
106106
foldTypeCaseDefs(foldTypeTree(boundopt.fold(x)(foldTypeTree(x, _)), selector), cases)
107+
case SyntheticBounds() => x
107108
case TypeBoundsTree(lo, hi) => foldTypeTree(foldTypeTree(x, lo), hi)
108109
}
109110

project/Build.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,9 @@ object Build {
393393
baseDirectory in Test := baseDirectory.value / "..",
394394
unmanagedSourceDirectories in Test += baseDirectory.value / "input" / "src" / "main" / "scala",
395395
libraryDependencies ++= List(
396-
("org.scalameta" %% "semanticdb" % "4.0.0" % Compile).withDottyCompat(scalaVersion.value),
397-
"com.novocode" % "junit-interface" % "0.11" % Compile,
398-
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0" % Compile,
399-
("org.scalameta" %% "semanticdb" % "4.0.0" % Test).withDottyCompat(scalaVersion.value),
400-
"com.novocode" % "junit-interface" % "0.11" % Test,
401-
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0" % Test
396+
("org.scalameta" %% "semanticdb" % "4.0.0").withDottyCompat(scalaVersion.value),
397+
"com.novocode" % "junit-interface" % "0.11",
398+
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0"
402399
)
403400
)
404401

semanticdb/Makefile

Lines changed: 0 additions & 11 deletions
This file was deleted.

semanticdb/input/src/main/scala/example/Example.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ class Example {
1414
x +
1515
y
1616
)
17+
}
18+
19+
class ExampleInit() {
20+
1721
}

semanticdb/readme.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ sbt
1010
> compile
1111
```
1212

13-
You will also need to generate the tasty files for the test. For now, you can
14-
easily do it by executing the makefile in this folder:
15-
```
16-
make
17-
```
18-
Please note that the makefile will also compile the `semanticdb/input` project.
19-
20-
2113
In the second terminal, run `sbt dotty-semanticdb/test` from the main dotty
2214
build
2315

semanticdb/src/dotty/semanticdb/SemanticdbConsumer.scala

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import scala.tasty.file.TastyConsumer
55

66
import dotty.tools.dotc.tastyreflect
77
import scala.collection.mutable.HashMap
8+
import scala.collection.mutable.Set
89
import scala.meta.internal.{semanticdb => s}
910
import dotty.semanticdb.Scala.{Descriptor => d}
1011
import dotty.semanticdb.Scala._
@@ -18,16 +19,25 @@ class SemanticdbConsumer extends TastyConsumer {
1819
def toSemanticdb(text: String): s.TextDocument = {
1920
s.TextDocument(text = text, occurrences = occurrences)
2021
}
22+
val package_definitions: Set[String] = Set()
2123

2224
final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
2325
import reflect._
2426

27+
val symbolsCache: HashMap[Symbol, String] = HashMap()
28+
2529
object ChildTraverser extends TreeTraverser {
2630
var children: List[Tree] = Nil
27-
override def traverseTree(tree: Tree)(implicit ctx: Context): Unit = children = tree::children
28-
override def traversePattern(pattern: Pattern)(implicit ctx: Context): Unit = ()
29-
override def traverseTypeTree(tree: TypeOrBoundsTree)(implicit ctx: Context): Unit = ()
30-
override def traverseCaseDef(tree: CaseDef)(implicit ctx: Context): Unit = ()
31+
override def traverseTree(tree: Tree)(implicit ctx: Context): Unit =
32+
children = tree :: children
33+
override def traversePattern(pattern: Pattern)(
34+
implicit ctx: Context): Unit = ()
35+
override def traverseTypeTree(tree: TypeOrBoundsTree)(
36+
implicit ctx: Context): Unit = ()
37+
override def traverseCaseDef(tree: CaseDef)(implicit ctx: Context): Unit =
38+
()
39+
override def traverseTypeCaseDef(tree: TypeCaseDef)(implicit ctx: Context): Unit =
40+
()
3141

3242
def getChildren(tree: Tree)(implicit ctx: Context): List[Tree] = {
3343
children = Nil
@@ -37,7 +47,6 @@ class SemanticdbConsumer extends TastyConsumer {
3747
}
3848

3949
object Traverser extends TreeTraverser {
40-
val symbolsCache: HashMap[Symbol, String] = HashMap()
4150
implicit class TreeExtender(tree: Tree) {
4251
def isUserCreated: Boolean = {
4352
val children: List[Position] =
@@ -86,21 +95,21 @@ class SemanticdbConsumer extends TastyConsumer {
8695

8796
def resolveClass(symbol: ClassSymbol): Symbol =
8897
(symbol.companionClass, symbol.companionModule) match {
89-
case (_, Some(module)) if symbol.flags.isObject => module
90-
case (Some(c), _) => c
91-
case _ => symbol
98+
case (_, Some(module)) if symbol.flags.isObject => module
99+
case (Some(c), _) => c
100+
case _ => symbol
92101
}
93102

94103
def disimbiguate(symbol_path: String, symbol: Symbol): String = {
95104
val symbolcl = resolveClass(symbol.owner.asClass)
96105
val methods = symbolcl.asClass.method(symbol.name)
97106
val (methods_count, method_pos) =
98-
methods.foldLeft((0, -1))((x:Tuple2[Int, Int], m:Symbol) => {
107+
methods.foldLeft((0, -1))((x: Tuple2[Int, Int], m: Symbol) => {
99108
if (m == symbol)
100-
(x._1+1, x._1)
101-
else
102-
(x._1+1, x._2)
103-
})
109+
(x._1 + 1, x._1)
110+
else
111+
(x._1 + 1, x._2)
112+
})
104113
val real_pos = methods_count - method_pos - 1
105114

106115
if (real_pos == 0) {
@@ -262,9 +271,12 @@ class SemanticdbConsumer extends TastyConsumer {
262271
super.traverseTree(tree)
263272
}
264273
case PackageClause(_) =>
265-
addOccurenceTree(tree,
266-
s.SymbolOccurrence.Role.REFERENCE,
267-
range(tree, tree.pos, tree.symbol.name))
274+
if (!package_definitions(tree.symbol.name)) {
275+
addOccurenceTree(tree,
276+
s.SymbolOccurrence.Role.REFERENCE,
277+
range(tree, tree.pos, tree.symbol.name))
278+
package_definitions += tree.symbol.name
279+
}
268280
super.traverseTree(tree)
269281

270282
case tree =>

semanticdb/test/dotty/semanticdb/Tests.scala

Lines changed: 120 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,138 @@ package dotty.semanticdb
22

33
import scala.tasty.Reflection
44
import scala.tasty.file._
5+
import scala.collection.mutable.HashMap
56

67
import org.junit.Test
78
import org.junit.Assert._
89
import java.nio.file._
910
import scala.meta.internal.{semanticdb => s}
1011
import scala.collection.JavaConverters._
12+
import java.io.File
13+
import scala.tasty.Reflection
14+
import scala.tasty.file.TastyConsumer
15+
import java.lang.reflect.InvocationTargetException
16+
17+
class TastyInspecter extends TastyConsumer {
18+
var source_path: Option[String] = None
19+
final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
20+
import reflect._
21+
object ChildTraverser extends TreeTraverser {
22+
override def traverseTree(tree: Tree)(implicit ctx: Context): Unit =
23+
tree match {
24+
case IsClassDef(cdef) => {
25+
cdef.symbol.annots.foreach { annot =>
26+
annot match {
27+
case Term.Apply(Term.Select(Term.New(t), _, _),
28+
List(Term.Literal(Constant.String(path))))
29+
if t.symbol.name == "SourceFile" =>
30+
// we found the path to a file. In this case, we do not need to
31+
// continue traversing the tree
32+
source_path = Some(path)
33+
case x => super.traverseTree(tree)
34+
}
35+
true
36+
}
37+
}
38+
case _ => {
39+
if (source_path == None)
40+
super.traverseTree(tree)
41+
else
42+
()
43+
}
44+
}
45+
}
46+
ChildTraverser.traverseTree(root)(reflect.rootContext)
47+
}
48+
}
1149

1250
class Tests {
1351

1452
// TODO: update scala-0.10 on version change (or resolve automatically)
15-
final def tastyClassDirectory = "out/bootstrap/dotty-semanticdb/scala-0.11/test-classes"
53+
final def tastyClassDirectory =
54+
"out/bootstrap/dotty-semanticdb/scala-0.11/test-classes"
1655
val sourceroot = Paths.get("semanticdb", "input").toAbsolutePath
1756
val sourceDirectory = sourceroot.resolve("src/main/scala")
1857

1958
val semanticdbClassDirectory = sourceroot.resolve("target/scala-2.12/classes")
20-
val semanticdbLoader = new Semanticdbs.Loader(sourceroot, List(semanticdbClassDirectory))
59+
val semanticdbLoader =
60+
new Semanticdbs.Loader(sourceroot, List(semanticdbClassDirectory))
61+
62+
val source_to_tasty =
63+
getTastyFiles(
64+
Paths.get("out", "bootstrap", "dotty-semanticdb/").toAbsolutePath)
65+
2166
/** Returns the SemanticDB for this Scala source file. */
2267
def getScalacSemanticdb(scalaFile: Path): s.TextDocument = {
2368
semanticdbLoader.resolve(scalaFile).get
2469
}
2570

26-
/** TODO: Produce semanticdb from TASTy for this Scala source file. */
27-
def getTastySemanticdb(scalaFile: Path): s.TextDocument = {
28-
val scalac = getScalacSemanticdb(scalaFile)
29-
val pat = """(.*)\.scala""".r
30-
val classpath = scalaFile.getParent().toString()
31-
val modulename = sourceDirectory.relativize(scalaFile).getParent().getFileName().toString()
71+
/** List all tasty files occuring in the folder f or one of its subfolders */
72+
def recursiveListFiles(f: File): Array[File] = {
73+
val pattern = ".*test-classes/example.*\\.tasty".r
74+
val files = f.listFiles
75+
val folders = files.filter(_.isDirectory)
76+
val tastyfiles = files.filter(_.toString match {
77+
case pattern(x: _*) => true
78+
case _ => false
79+
})
80+
tastyfiles ++ folders.flatMap(recursiveListFiles)
81+
}
82+
83+
/** Returns a mapping from *.scala file to a list of tasty files. */
84+
def getTastyFiles(artifactsPath: Path): HashMap[String, List[Path]] = {
85+
val source_to_tasty: HashMap[String, List[Path]] = HashMap()
86+
val tastyfiles = recursiveListFiles(artifactsPath.toFile())
87+
recursiveListFiles(artifactsPath.toFile()).map(tasty_path => {
88+
val (classpath, classname) = getClasspathClassname(tasty_path.toPath())
89+
// We add an exception here to avoid crashing if we encountered
90+
// a bad tasty file
91+
try {
92+
val inspecter = new TastyInspecter
93+
ConsumeTasty(classpath, classname :: Nil, inspecter)
94+
inspecter.source_path.foreach(
95+
source =>
96+
source_to_tasty +=
97+
(source -> (tasty_path
98+
.toPath() :: source_to_tasty.getOrElse(source, Nil))))
99+
} catch {
100+
case _: InvocationTargetException => println(tasty_path)
101+
}
102+
})
103+
source_to_tasty
104+
}
105+
106+
/** Infers a tuple (class path, class name) from a given path */
107+
def getClasspathClassname(file: Path): (String, String) = {
108+
val pat = """(.*)\..*""".r
109+
val classpath = file.getParent().getParent().toString()
110+
val modulename = file.getParent().getFileName().toString()
32111
val sourcename =
33-
scalaFile.toFile().getName().toString() match {
34-
case pat(name) => name
35-
case _ => ""
112+
file.toFile().getName().toString() match {
113+
case pat(name) => name
114+
case _ => ""
36115
}
37-
val sdbconsumer = new SemanticdbConsumer
38-
val _ = ConsumeTasty(classpath, (modulename + "." + sourcename) :: Nil, sdbconsumer)
39-
sdbconsumer.toSemanticdb(scalac.text)
116+
return (classpath, modulename + "." + sourcename)
117+
}
40118

119+
def getTastySemanticdb(scalaFile: Path): s.TextDocument = {
120+
val scalac = getScalacSemanticdb(scalaFile)
121+
122+
val tasty_files = source_to_tasty.getOrElse(
123+
sourceDirectory.resolve(scalaFile).toString,
124+
Nil)
125+
126+
val tasty_classes = tasty_files.map(getClasspathClassname)
127+
// If we have more than one classpath then something went wrong
128+
if (tasty_classes.groupBy((a, _) => a).size != 1) {
129+
scalac
130+
} else {
131+
val (classpaths, classnames) = tasty_classes.unzip
132+
val sdbconsumer = new SemanticdbConsumer
133+
134+
val _ = ConsumeTasty(classpaths.head, classnames, sdbconsumer)
135+
sdbconsumer.toSemanticdb(scalac.text)
136+
}
41137
}
42138

43139
/** Fails the test if the s.TextDocument from tasty and semanticdb-scalac are not the same. */
@@ -61,9 +157,16 @@ class Tests {
61157
val diff =
62158
if (patch.getDeltas.isEmpty) ""
63159
else {
64-
difflib.DiffUtils.generateUnifiedDiff(
65-
"tasty", "scala2", obtainedLines, patch, 1
66-
).asScala.mkString("\n")
160+
difflib.DiffUtils
161+
.generateUnifiedDiff(
162+
"tasty",
163+
"scala2",
164+
obtainedLines,
165+
patch,
166+
1
167+
)
168+
.asScala
169+
.mkString("\n")
67170
}
68171
if (!diff.isEmpty) {
69172
fail("\n" + diff)

0 commit comments

Comments
 (0)