Skip to content

Commit 6751616

Browse files
committed
Fix #5223: Add tasty interpolator in IDE tests
This interpolator is used to defined virtual source files that will be compiled before the test starts running. Unlike virtual source files defined with `code`, the ones defined with `tasty` will not be opened in the IDE (`textDocument/didOpen` will not be sent to the LSP server). As a result, the language server will unpickle the trees from TASTY. Fixes #5223
1 parent 93fcd94 commit 6751616

File tree

4 files changed

+61
-13
lines changed

4 files changed

+61
-13
lines changed

language-server/test/dotty/tools/languageserver/DefinitionTest.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,15 @@ class DefinitionTest {
208208
.definition(m9 to m10, List(m3 to m4))
209209
}
210210

211+
@Test def definitionFromTasty: Unit = {
212+
withSources(
213+
tasty"""package mypackage
214+
class ${m1}A${m2}""",
215+
code"""package mypackage
216+
object O {
217+
new ${m3}A${m4}
218+
}"""
219+
).definition(m3 to m4, List(m1 to m2))
220+
}
221+
211222
}

language-server/test/dotty/tools/languageserver/util/Code.scala

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ object Code {
6060
WorksheetWithPositions(text, positions)
6161
}
6262

63+
/**
64+
* An interpolator similar to `code`, but used for defining a source that will
65+
* be unpickled from TASTY.
66+
*
67+
* @see code
68+
*/
69+
def tasty(args: Embedded*): TastyWithPositions = {
70+
val (text, positions) = textAndPositions(args: _*)
71+
TastyWithPositions(text, positions)
72+
}
73+
6374
private def textAndPositions(args: Embedded*): (String, List[(CodeMarker, Int, Int)]) = {
6475
val pi = sc.parts.iterator
6576
val ai = args.iterator
@@ -107,7 +118,10 @@ object Code {
107118

108119
sealed trait SourceWithPositions {
109120

110-
/** The code contained within the virtual source file. */
121+
/** A name for this source given its index. */
122+
def sourceName(index: Int): String
123+
124+
/** The code contained within the virtual source file. */
111125
def text: String
112126

113127
/** The positions of the markers that have been set. */
@@ -124,15 +138,29 @@ object Code {
124138
* @param text The code contained within the virtual source file.
125139
* @param positions The positions of the markers that have been set.
126140
*/
127-
case class ScalaSourceWithPositions(text: String, positions: List[(CodeMarker, Int, Int)]) extends SourceWithPositions
141+
case class ScalaSourceWithPositions(text: String, positions: List[(CodeMarker, Int, Int)]) extends SourceWithPositions {
142+
def sourceName(index: Int): String = s"Source$index.scala"
143+
}
128144

129145
/**
130146
* A virtual worksheet where several markers have been set.
131147
*
132148
* @param text The code contained within the virtual source file.
133149
* @param positions The positions of the markers that have been set.
134150
*/
135-
case class WorksheetWithPositions(text: String, positions: List[(CodeMarker, Int, Int)]) extends SourceWithPositions
151+
case class WorksheetWithPositions(text: String, positions: List[(CodeMarker, Int, Int)]) extends SourceWithPositions {
152+
def sourceName(index: Int): String = s"Worksheet$index.sc"
153+
}
154+
155+
/**
156+
* A virtual source file that will not be opened in the IDE, but instead unpickled from TASTY.
157+
*
158+
* @param text The code contained within the virtual source file.
159+
* @param positions The positions of the markers that have been set.
160+
*/
161+
case class TastyWithPositions(text: String, positions: List[(CodeMarker, Int, Int)]) extends SourceWithPositions {
162+
def sourceName(index: Int): String = s"Source-from-tasty-$index.scala"
163+
}
136164

137165
/**
138166
* A group of sources belonging to the same project.

language-server/test/dotty/tools/languageserver/util/CodeTester.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class CodeTester(workspaces: List[Workspace]) {
2121
private val files =
2222
for { workspace <- workspaces
2323
(source, id) <- workspace.sources.zipWithIndex } yield source match {
24-
case ScalaSourceWithPositions(text, _) => testServer.openCode(text, workspace, s"Source$id.scala")
25-
case WorksheetWithPositions(text, _) => testServer.openCode(text, workspace, s"Worksheet$id.sc")
24+
case src @ TastyWithPositions(text, _) => testServer.openCode(text, workspace, src.sourceName(id), openInIDE = false)
25+
case other => testServer.openCode(other.text, workspace, other.sourceName(id), openInIDE = true)
2626
}
2727

2828
private val positions: PositionContext = getPositions(files)

language-server/test/dotty/tools/languageserver/util/server/TestServer.scala

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import dotty.tools.dotc.Main
1010
import dotty.tools.dotc.reporting.{Reporter, ThrowingReporter}
1111
import dotty.tools.io.Directory
1212
import dotty.tools.languageserver.DottyLanguageServer
13-
import dotty.tools.languageserver.util.Code.Workspace
13+
import dotty.tools.languageserver.util.Code.{TastyWithPositions, Workspace}
1414
import org.eclipse.lsp4j.{ DidOpenTextDocumentParams, InitializeParams, InitializeResult, TextDocumentItem}
1515

1616
class TestServer(testFolder: Path, workspaces: List[Workspace]) {
@@ -46,8 +46,12 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
4646
.map(elem => '"' + elem.toString.replace('\\', '/') + '"')
4747
.mkString("[ ", ", ", " ]")
4848

49-
// Compile all the dependencies of this workspace
50-
workspace.dependsOn.foreach(compileWorkspaceAndDependencies)
49+
if (workspace.sources.exists(_.isInstanceOf[TastyWithPositions])) {
50+
compileWorkspaceAndDependencies(workspace)
51+
} else {
52+
// Compile all the dependencies of this workspace
53+
workspace.dependsOn.foreach(compileWorkspaceAndDependencies)
54+
}
5155

5256
s"""{
5357
| "id" : "${workspace.name}",
@@ -80,16 +84,21 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
8084
/** Open the code in the given file and returns the file.
8185
* @param code code in file
8286
* @param fileName file path in the source directory
87+
* @param openInIDE If true, send `textDocument/didOpen` to the server.
8388
* @return the file opened
8489
*/
85-
def openCode(code: String, workspace: Workspace, fileName: String): TestFile = {
90+
def openCode(code: String, workspace: Workspace, fileName: String, openInIDE: Boolean): TestFile = {
8691
val testFile = new TestFile(workspace.name + separator + fileName)
87-
val dotdp = new DidOpenTextDocumentParams()
8892
val tdi = new TextDocumentItem()
8993
tdi.setUri(testFile.uri)
9094
tdi.setText(code)
91-
dotdp.setTextDocument(tdi)
92-
server.didOpen(dotdp)
95+
96+
if (openInIDE) {
97+
val dotdp = new DidOpenTextDocumentParams()
98+
dotdp.setTextDocument(tdi)
99+
server.didOpen(dotdp)
100+
}
101+
93102
testFile
94103
}
95104

@@ -127,7 +136,7 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
127136
private def compileWorkspace(workspace: Workspace): Unit = {
128137
val sourcesDir = sourceDirectory(workspace, wipe = true)
129138
val sources = workspace.sources.zipWithIndex.map { case (src, id) =>
130-
val path = sourcesDir.resolve(s"Source${id}.scala").toAbsolutePath
139+
val path = sourcesDir.resolve(src.sourceName(id)).toAbsolutePath
131140
Files.write(path, src.text.getBytes("UTF-8"))
132141
path.toString
133142
}

0 commit comments

Comments
 (0)