Skip to content

Commit bdece5c

Browse files
committed
Move test-only SemanticDB code to test sources
1 parent c245c02 commit bdece5c

2 files changed

Lines changed: 139 additions & 139 deletions

File tree

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package dotty.tools.dotc.semanticdb
22

33
import java.nio.file.*
4-
import java.nio.charset.StandardCharsets
54
import scala.jdk.CollectionConverters.*
6-
import dotty.tools.dotc.util.SourceFile
7-
import dotty.tools.dotc.semanticdb.Scala3.given
85

96
private[semanticdb] object Tools:
107

@@ -16,135 +13,3 @@ private[semanticdb] object Tools:
1613
// parser into treating it as an absolute path, and then strip the spurious leading slash from the final result.
1714
val uriParts = for part <- path.asScala yield new java.net.URI(null, null, "/" + part.toString, null)
1815
uriParts.mkString.stripPrefix("/")
19-
20-
/** Load SemanticDB TextDocument for a single Scala source file
21-
*
22-
* @param scalaAbsolutePath Absolute path to a Scala source file.
23-
* @param scalaRelativePath scalaAbsolutePath relativized by the sourceroot.
24-
* @param semanticdbAbsolutePath Absolute path to the SemanticDB file.
25-
*/
26-
def loadTextDocument(
27-
scalaAbsolutePath: Path,
28-
scalaRelativePath: Path,
29-
semanticdbAbsolutePath: Path
30-
): TextDocument =
31-
val reluri = mkURIstring(scalaRelativePath)
32-
val sdocs = parseTextDocuments(semanticdbAbsolutePath)
33-
sdocs.documents.find(_.uri == reluri) match
34-
case None => throw new NoSuchElementException(s"$scalaRelativePath")
35-
case Some(document) =>
36-
val text = new String(Files.readAllBytes(scalaAbsolutePath), StandardCharsets.UTF_8)
37-
// Assert the SemanticDB payload is in-sync with the contents of the Scala file on disk.
38-
val md5FingerprintOnDisk = internal.MD5.compute(text)
39-
if document.md5 != md5FingerprintOnDisk then
40-
throw new IllegalArgumentException(s"stale semanticdb: $scalaRelativePath")
41-
else
42-
// Update text document to include full text contents of the file.
43-
document.copy(text = text)
44-
end loadTextDocument
45-
46-
def loadTextDocumentUnsafe(scalaAbsolutePath: Path, semanticdbAbsolutePath: Path): TextDocument =
47-
val docs = parseTextDocuments(semanticdbAbsolutePath).documents
48-
assert(docs.length == 1)
49-
docs.head.copy(text = new String(Files.readAllBytes(scalaAbsolutePath), StandardCharsets.UTF_8))
50-
51-
/** Parses SemanticDB text documents from an absolute path to a `*.semanticdb` file. */
52-
private def parseTextDocuments(path: Path): TextDocuments =
53-
val bytes = Files.readAllBytes(path).nn // NOTE: a semanticdb file is a TextDocuments message, not TextDocument
54-
TextDocuments.parseFrom(bytes)
55-
56-
def metac(doc: TextDocument, realPath: Path)(using sb: StringBuilder): StringBuilder =
57-
val symtab = PrinterSymtab.fromTextDocument(doc)
58-
val symPrinter = SymbolInformationPrinter(symtab)
59-
val realURI = realPath.toString
60-
given sourceFile: SourceFile = SourceFile.virtual(doc.uri, doc.text)
61-
val synthPrinter = SyntheticPrinter(symtab, sourceFile)
62-
sb.append(realURI).nl
63-
sb.append("-" * realURI.length).nl
64-
sb.nl
65-
sb.append("Summary:").nl
66-
sb.append("Schema => ").append(schemaString(doc.schema)).nl
67-
sb.append("Uri => ").append(doc.uri).nl
68-
sb.append("Text => empty").nl
69-
sb.append("Language => ").append(languageString(doc.language)).nl
70-
sb.append("Symbols => ").append(doc.symbols.length).append(" entries").nl
71-
sb.append("Occurrences => ").append(doc.occurrences.length).append(" entries").nl
72-
if doc.diagnostics.nonEmpty then
73-
sb.append("Diagnostics => ").append(doc.diagnostics.length).append(" entries").nl
74-
if doc.synthetics.nonEmpty then
75-
sb.append("Synthetics => ").append(doc.synthetics.length).append(" entries").nl
76-
sb.nl
77-
sb.append("Symbols:").nl
78-
doc.symbols.sorted.foreach(s => processSymbol(s, symPrinter))
79-
sb.nl
80-
sb.append("Occurrences:").nl
81-
doc.occurrences.sorted.foreach(processOccurrence)
82-
sb.nl
83-
if doc.diagnostics.nonEmpty then
84-
sb.append("Diagnostics:").nl
85-
doc.diagnostics.sorted.foreach(d => processDiag(d))
86-
sb.nl
87-
if doc.synthetics.nonEmpty then
88-
sb.append("Synthetics:").nl
89-
doc.synthetics.sorted.foreach(s => processSynth(s, synthPrinter))
90-
sb.nl
91-
sb
92-
end metac
93-
94-
private def schemaString(schema: Schema) =
95-
import Schema.*
96-
schema match
97-
case SEMANTICDB3 => "SemanticDB v3"
98-
case SEMANTICDB4 => "SemanticDB v4"
99-
case LEGACY => "SemanticDB legacy"
100-
case Unrecognized(_) => "unknown"
101-
end schemaString
102-
103-
private def languageString(language: Language) =
104-
import Language.*
105-
language match
106-
case SCALA => "Scala"
107-
case JAVA => "Java"
108-
case UNKNOWN_LANGUAGE | Unrecognized(_) => "unknown"
109-
end languageString
110-
111-
private def processSymbol(info: SymbolInformation, printer: SymbolInformationPrinter)(using sb: StringBuilder): Unit =
112-
sb.append(printer.pprintSymbolInformation(info)).nl
113-
114-
private def processSynth(synth: Synthetic, printer: SyntheticPrinter)(using sb: StringBuilder): Unit =
115-
sb.append(printer.pprint(synth)).nl
116-
117-
private def processDiag(d: Diagnostic)(using sb: StringBuilder): Unit =
118-
d.range match
119-
case Some(range) => processRange(sb, range)
120-
case _ => sb.append("[):")
121-
sb.append(" ")
122-
d.severity match
123-
case Diagnostic.Severity.ERROR => sb.append("[error]")
124-
case Diagnostic.Severity.WARNING => sb.append("[warning]")
125-
case Diagnostic.Severity.INFORMATION => sb.append("[info]")
126-
case _ => sb.append("[unknown]")
127-
sb.append(" ")
128-
sb.append(d.message)
129-
sb.nl
130-
131-
private def processOccurrence(occ: SymbolOccurrence)(using sb: StringBuilder, sourceFile: SourceFile): Unit =
132-
occ.range match
133-
case Some(range) =>
134-
processRange(sb, range)
135-
if range.endLine == range.startLine
136-
&& range.startCharacter != range.endCharacter
137-
&& !(occ.symbol.isConstructor && occ.role.isDefinition) then
138-
val line = sourceFile.lineContent(sourceFile.lineToOffset(range.startLine))
139-
assert(range.startCharacter <= line.length && range.endCharacter <= line.length,
140-
s"Line is only ${line.length} - start line was ${range.startLine} in source ${sourceFile.name}"
141-
)
142-
sb.append(" ").append(line.substring(range.startCharacter, range.endCharacter))
143-
case _ =>
144-
sb.append("[):")
145-
end match
146-
sb.append(if occ.role.isReference then " -> " else " <- ").append(occ.symbol).nl
147-
end processOccurrence
148-
149-
extension (sb: StringBuilder)
150-
private inline def nl = sb.append(System.lineSeparator)

compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ import dotty.tools.dotc.util.SourceFile
4343
files.head
4444
val metacSb: StringBuilder = StringBuilder(5000)
4545
val semanticdbPath = inputFile()
46-
val doc = Tools.loadTextDocumentUnsafe(sourceSrc.toAbsolutePath, semanticdbPath)
47-
Tools.metac(doc, Paths.get(doc.uri))(using metacSb)
46+
val doc = SemanticdbTests.loadTextDocumentUnsafe(sourceSrc.toAbsolutePath, semanticdbPath)
47+
SemanticdbTests.metac(doc, Paths.get(doc.uri))(using metacSb)
4848
Files.write(rootSrc.resolve("metac.expect"), metacSb.toString.getBytes(StandardCharsets.UTF_8))
4949

5050

@@ -85,8 +85,8 @@ class SemanticdbTests:
8585
.resolve(relpath)
8686
.resolveSibling(filename + ".semanticdb")
8787
val expectPath = source.resolveSibling(filename.replace(".scala", ".expect.scala"))
88-
val doc = Tools.loadTextDocument(source, relpath, semanticdbPath)
89-
Tools.metac(doc, rootSrc.relativize(source))(using metacSb)
88+
val doc = SemanticdbTests.loadTextDocument(source, relpath, semanticdbPath)
89+
SemanticdbTests.metac(doc, rootSrc.relativize(source))(using metacSb)
9090
val obtained = trimTrailingWhitespace(SemanticdbTests.printTextDocument(doc))
9191
collectErrorOrUpdate(expectPath, obtained)
9292
collectErrorOrUpdate(metacExpectFile, metacSb.toString)
@@ -157,4 +157,139 @@ object SemanticdbTests:
157157
out.flush()
158158
DocumentPrinter.textDocumentPrettyPrint(byteStream.toByteArray.nn)
159159
end printTextDocument
160+
161+
162+
/** Load SemanticDB TextDocument for a single Scala source file
163+
*
164+
* @param scalaAbsolutePath Absolute path to a Scala source file.
165+
* @param scalaRelativePath scalaAbsolutePath relativized by the sourceroot.
166+
* @param semanticdbAbsolutePath Absolute path to the SemanticDB file.
167+
*/
168+
def loadTextDocument(
169+
scalaAbsolutePath: Path,
170+
scalaRelativePath: Path,
171+
semanticdbAbsolutePath: Path
172+
): TextDocument =
173+
val reluri = Tools.mkURIstring(scalaRelativePath)
174+
val sdocs = parseTextDocuments(semanticdbAbsolutePath)
175+
sdocs.documents.find(_.uri == reluri) match
176+
case None => throw new NoSuchElementException(s"$scalaRelativePath")
177+
case Some(document) =>
178+
val text = new String(Files.readAllBytes(scalaAbsolutePath), StandardCharsets.UTF_8)
179+
// Assert the SemanticDB payload is in-sync with the contents of the Scala file on disk.
180+
val md5FingerprintOnDisk = internal.MD5.compute(text)
181+
if document.md5 != md5FingerprintOnDisk then
182+
throw new IllegalArgumentException(s"stale semanticdb: $scalaRelativePath")
183+
else
184+
// Update text document to include full text contents of the file.
185+
document.copy(text = text)
186+
end loadTextDocument
187+
188+
def loadTextDocumentUnsafe(scalaAbsolutePath: Path, semanticdbAbsolutePath: Path): TextDocument =
189+
val docs = parseTextDocuments(semanticdbAbsolutePath).documents
190+
assert(docs.length == 1)
191+
docs.head.copy(text = new String(Files.readAllBytes(scalaAbsolutePath), StandardCharsets.UTF_8))
192+
193+
/** Parses SemanticDB text documents from an absolute path to a `*.semanticdb` file. */
194+
private def parseTextDocuments(path: Path): TextDocuments =
195+
val bytes = Files.readAllBytes(path).nn // NOTE: a semanticdb file is a TextDocuments message, not TextDocument
196+
TextDocuments.parseFrom(bytes)
197+
198+
199+
def metac(doc: TextDocument, realPath: Path)(using sb: StringBuilder): StringBuilder =
200+
val symtab = PrinterSymtab.fromTextDocument(doc)
201+
val symPrinter = SymbolInformationPrinter(symtab)
202+
val realURI = realPath.toString
203+
given sourceFile: SourceFile = SourceFile.virtual(doc.uri, doc.text)
204+
val synthPrinter = SyntheticPrinter(symtab, sourceFile)
205+
sb.append(realURI).nl
206+
sb.append("-" * realURI.length).nl
207+
sb.nl
208+
sb.append("Summary:").nl
209+
sb.append("Schema => ").append(schemaString(doc.schema)).nl
210+
sb.append("Uri => ").append(doc.uri).nl
211+
sb.append("Text => empty").nl
212+
sb.append("Language => ").append(languageString(doc.language)).nl
213+
sb.append("Symbols => ").append(doc.symbols.length).append(" entries").nl
214+
sb.append("Occurrences => ").append(doc.occurrences.length).append(" entries").nl
215+
if doc.diagnostics.nonEmpty then
216+
sb.append("Diagnostics => ").append(doc.diagnostics.length).append(" entries").nl
217+
if doc.synthetics.nonEmpty then
218+
sb.append("Synthetics => ").append(doc.synthetics.length).append(" entries").nl
219+
sb.nl
220+
sb.append("Symbols:").nl
221+
doc.symbols.sorted.foreach(s => processSymbol(s, symPrinter))
222+
sb.nl
223+
sb.append("Occurrences:").nl
224+
doc.occurrences.sorted.foreach(processOccurrence)
225+
sb.nl
226+
if doc.diagnostics.nonEmpty then
227+
sb.append("Diagnostics:").nl
228+
doc.diagnostics.sorted.foreach(d => processDiag(d))
229+
sb.nl
230+
if doc.synthetics.nonEmpty then
231+
sb.append("Synthetics:").nl
232+
doc.synthetics.sorted.foreach(s => processSynth(s, synthPrinter))
233+
sb.nl
234+
sb
235+
end metac
236+
237+
private def schemaString(schema: Schema) =
238+
import Schema.*
239+
schema match
240+
case SEMANTICDB3 => "SemanticDB v3"
241+
case SEMANTICDB4 => "SemanticDB v4"
242+
case LEGACY => "SemanticDB legacy"
243+
case Unrecognized(_) => "unknown"
244+
end schemaString
245+
246+
private def languageString(language: Language) =
247+
import Language.*
248+
language match
249+
case SCALA => "Scala"
250+
case JAVA => "Java"
251+
case UNKNOWN_LANGUAGE | Unrecognized(_) => "unknown"
252+
end languageString
253+
254+
private def processSymbol(info: SymbolInformation, printer: SymbolInformationPrinter)(using sb: StringBuilder): Unit =
255+
sb.append(printer.pprintSymbolInformation(info)).nl
256+
257+
private def processSynth(synth: Synthetic, printer: SyntheticPrinter)(using sb: StringBuilder): Unit =
258+
sb.append(printer.pprint(synth)).nl
259+
260+
private def processDiag(d: Diagnostic)(using sb: StringBuilder): Unit =
261+
d.range match
262+
case Some(range) => processRange(sb, range)
263+
case _ => sb.append("[):")
264+
sb.append(" ")
265+
d.severity match
266+
case Diagnostic.Severity.ERROR => sb.append("[error]")
267+
case Diagnostic.Severity.WARNING => sb.append("[warning]")
268+
case Diagnostic.Severity.INFORMATION => sb.append("[info]")
269+
case _ => sb.append("[unknown]")
270+
sb.append(" ")
271+
sb.append(d.message)
272+
sb.nl
273+
274+
private def processOccurrence(occ: SymbolOccurrence)(using sb: StringBuilder, sourceFile: SourceFile): Unit =
275+
occ.range match
276+
case Some(range) =>
277+
processRange(sb, range)
278+
if range.endLine == range.startLine
279+
&& range.startCharacter != range.endCharacter
280+
&& !(occ.symbol.isConstructor && occ.role.isDefinition) then
281+
val line = sourceFile.lineContent(sourceFile.lineToOffset(range.startLine))
282+
assert(range.startCharacter <= line.length && range.endCharacter <= line.length,
283+
s"Line is only ${line.length} - start line was ${range.startLine} in source ${sourceFile.file.name}"
284+
)
285+
sb.append(" ").append(line.substring(range.startCharacter, range.endCharacter))
286+
case _ =>
287+
sb.append("[):")
288+
end match
289+
sb.append(if occ.role.isReference then " -> " else " <- ").append(occ.symbol).nl
290+
end processOccurrence
291+
292+
extension (sb: StringBuilder)
293+
private inline def nl = sb.append(System.lineSeparator)
294+
160295
end SemanticdbTests

0 commit comments

Comments
 (0)