@@ -25,16 +25,17 @@ import scala.PartialFunction.condOpt
25
25
26
26
import dotty .tools .dotc .{semanticdb => s }
27
27
import dotty .tools .io .{AbstractFile , JarArchive }
28
+ import dotty .tools .dotc .util .Property
29
+ import dotty .tools .dotc .semanticdb .DiagnosticOps .*
30
+
28
31
29
32
/** Extract symbol references and uses to semanticdb files.
30
33
* See https://scalameta.org/docs/semanticdb/specification.html#symbol-1
31
34
* for a description of the format.
32
- * TODO: Also extract type information
33
35
*/
34
- class ExtractSemanticDB extends Phase :
35
- import Scala3 .{_ , given }
36
+ class ExtractSemanticDB private (phaseMode : ExtractSemanticDB .PhaseMode , suffix : String , _key : Property .Key [TextDocument ]) extends Phase :
36
37
37
- override val phaseName : String = ExtractSemanticDB .name
38
+ override def phaseName : String = ExtractSemanticDB .phaseNamePrefix + suffix
38
39
39
40
override val description : String = ExtractSemanticDB .description
40
41
@@ -48,16 +49,94 @@ class ExtractSemanticDB extends Phase:
48
49
49
50
override def run (using Context ): Unit =
50
51
val unit = ctx.compilationUnit
51
- val extractor = Extractor ()
52
- extractor.extract(unit.tpdTree)
53
- ExtractSemanticDB .write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList, extractor.synthetics.toList)
52
+ if (phaseMode == ExtractSemanticDB .PhaseMode .PostTyper )
53
+ val extractor = ExtractSemanticDB .Extractor ()
54
+ extractor.extract(unit.tpdTree)
55
+ unit.tpdTree.putAttachment(_key, extractor.toTextDocument(unit.source))
56
+ else
57
+ unit.tpdTree.getAttachment(_key) match
58
+ case None => ???
59
+ case Some (doc) =>
60
+ val warnings = ctx.reporter.allWarnings.collect {
61
+ case w if w.pos.source == ctx.source => w.toSemanticDiagnostic
62
+ }
63
+ ExtractSemanticDB .write(unit.source, doc.copy(diagnostics = warnings))
64
+ end ExtractSemanticDB
65
+
66
+ object ExtractSemanticDB :
67
+ import java .nio .file .Path
68
+ import java .nio .file .Files
69
+ import java .nio .file .Paths
70
+
71
+ val phaseNamePrefix : String = " extractSemanticDB"
72
+ val description : String = " extract info into .semanticdb files"
73
+
74
+ enum PhaseMode :
75
+ case PostTyper
76
+ case PostInlining
77
+
78
+ /**
79
+ * The key used to retrieve the "unused entity" analysis metadata,
80
+ * from the compilation `Context`
81
+ */
82
+ private val _key = Property .StickyKey [TextDocument ]
83
+
84
+ class PostTyper extends ExtractSemanticDB (PhaseMode .PostTyper , " PostTyper" , _key)
85
+
86
+ class PostInlining extends ExtractSemanticDB (PhaseMode .PostInlining , " PostInlining" , _key)
87
+
88
+ private def semanticdbTarget (using Context ): Option [Path ] =
89
+ Option (ctx.settings.semanticdbTarget.value)
90
+ .filterNot(_.isEmpty)
91
+ .map(Paths .get(_))
92
+
93
+ private def outputDirectory (using Context ): AbstractFile = ctx.settings.outputDir.value
94
+
95
+ private def absolutePath (path : Path ): Path = path.toAbsolutePath.normalize
96
+
97
+ private def write (
98
+ source : SourceFile ,
99
+ doc : TextDocument
100
+ )(using Context ): Unit =
101
+ val relPath = SourceFile .relativePath(source, ctx.settings.sourceroot.value)
102
+ val outpath = absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
103
+ .resolve(" META-INF" )
104
+ .resolve(" semanticdb" )
105
+ .resolve(relPath)
106
+ .resolveSibling(source.name + " .semanticdb" )
107
+ Files .createDirectories(outpath.getParent())
108
+ val docs = TextDocuments (List (doc))
109
+ val out = Files .newOutputStream(outpath)
110
+ try
111
+ val stream = internal.SemanticdbOutputStream .newInstance(out)
112
+ docs.writeTo(stream)
113
+ stream.flush()
114
+ finally
115
+ out.close()
116
+ end write
117
+
54
118
55
119
/** Extractor of symbol occurrences from trees */
56
- class Extractor extends TreeTraverser :
120
+ private class Extractor extends TreeTraverser :
121
+ import Scala3 .{_ , given }
57
122
given s .SemanticSymbolBuilder = s.SemanticSymbolBuilder ()
58
123
val synth = SyntheticsExtractor ()
59
124
given converter : s.TypeOps = s.TypeOps ()
60
125
126
+
127
+ def toTextDocument (source : SourceFile )(using Context ): TextDocument =
128
+ val relPath = SourceFile .relativePath(source, ctx.settings.sourceroot.value)
129
+ TextDocument (
130
+ schema = Schema .SEMANTICDB4 ,
131
+ language = Language .SCALA ,
132
+ uri = Tools .mkURIstring(Paths .get(relPath)),
133
+ text = " " ,
134
+ md5 = internal.MD5 .compute(String (source.content)),
135
+ symbols = symbolInfos.toList,
136
+ occurrences = occurrences.toList,
137
+ synthetics = synthetics.toList,
138
+ )
139
+
61
140
/** The bodies of synthetic locals */
62
141
private val localBodies = mutable.HashMap [Symbol , Tree ]()
63
142
@@ -468,52 +547,5 @@ class ExtractSemanticDB extends Phase:
468
547
registerSymbol(vparam.symbol, symkinds)
469
548
traverse(vparam.tpt)
470
549
tparams.foreach(tp => traverse(tp.rhs))
471
-
472
-
473
- object ExtractSemanticDB :
474
- import java .nio .file .Path
475
- import java .nio .file .Files
476
- import java .nio .file .Paths
477
-
478
- val name : String = " extractSemanticDB"
479
- val description : String = " extract info into .semanticdb files"
480
-
481
- private def semanticdbTarget (using Context ): Option [Path ] =
482
- Option (ctx.settings.semanticdbTarget.value)
483
- .filterNot(_.isEmpty)
484
- .map(Paths .get(_))
485
-
486
- private def outputDirectory (using Context ): AbstractFile = ctx.settings.outputDir.value
487
-
488
- def write (
489
- source : SourceFile ,
490
- occurrences : List [SymbolOccurrence ],
491
- symbolInfos : List [SymbolInformation ],
492
- synthetics : List [Synthetic ],
493
- )(using Context ): Unit =
494
- def absolutePath (path : Path ): Path = path.toAbsolutePath.normalize
495
- val relPath = SourceFile .relativePath(source, ctx.settings.sourceroot.value)
496
- val outpath = absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
497
- .resolve(" META-INF" )
498
- .resolve(" semanticdb" )
499
- .resolve(relPath)
500
- .resolveSibling(source.name + " .semanticdb" )
501
- Files .createDirectories(outpath.getParent())
502
- val doc : TextDocument = TextDocument (
503
- schema = Schema .SEMANTICDB4 ,
504
- language = Language .SCALA ,
505
- uri = Tools .mkURIstring(Paths .get(relPath)),
506
- text = " " ,
507
- md5 = internal.MD5 .compute(String (source.content)),
508
- symbols = symbolInfos,
509
- occurrences = occurrences,
510
- synthetics = synthetics,
511
- )
512
- val docs = TextDocuments (List (doc))
513
- val out = Files .newOutputStream(outpath)
514
- try
515
- val stream = internal.SemanticdbOutputStream .newInstance(out)
516
- docs.writeTo(stream)
517
- stream.flush()
518
- finally
519
- out.close()
550
+ end Extractor
551
+ end ExtractSemanticDB
0 commit comments