@@ -5,8 +5,8 @@ import dotty.tools.dotc.{semanticdb => s}
5
5
import scala .collection .mutable
6
6
import dotty .tools .dotc .semanticdb .Scala3 .{_ , given }
7
7
import SymbolInformation .Kind ._
8
-
9
- class SymbolInfomationPrinter (symtab : PrinterSymtab ):
8
+ import dotty . tools . dotc . util . SourceFile
9
+ class SymbolInformationPrinter (symtab : PrinterSymtab ):
10
10
val notes = InfoNotes ()
11
11
val infoPrinter = InfoPrinter (notes)
12
12
@@ -28,8 +28,9 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
28
28
val displayName = if sym.isGlobal then sym.desc.value else sym
29
29
SymbolInformation (symbol = sym, displayName = displayName)
30
30
}
31
+ end InfoNotes
31
32
32
- class InfoPrinter (notes : InfoNotes ) {
33
+ class InfoPrinter (notes : InfoNotes ):
33
34
private enum SymbolStyle :
34
35
case Reference , Definition
35
36
def pprint (info : SymbolInformation ): String =
@@ -81,7 +82,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
81
82
private def pprintDef (info : SymbolInformation ) =
82
83
notes.enter(info)
83
84
pprint(info.symbol, SymbolStyle .Definition )
84
- private def pprintRef (sym : String ): String = pprint(sym, SymbolStyle .Reference )
85
+ def pprintRef (sym : String ): String = pprint(sym, SymbolStyle .Reference )
85
86
private def pprintDef (sym : String ): String = pprint(sym, SymbolStyle .Definition )
86
87
private def pprint (sym : String , style : SymbolStyle ): String =
87
88
val info = notes.visit(sym)
@@ -137,7 +138,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
137
138
case _ =>
138
139
" <?>"
139
140
140
- private def pprint (tpe : Type ): String = {
141
+ protected def pprint (tpe : Type ): String = {
141
142
def prefix (tpe : Type ): String = tpe match
142
143
case TypeRef (pre, sym, args) =>
143
144
val preStr = pre match {
@@ -204,7 +205,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
204
205
case tpe => s " @ ${pprint(tpe)}"
205
206
}
206
207
207
- private def pprint (const : Constant ): String = const match {
208
+ protected def pprint (const : Constant ): String = const match {
208
209
case Constant .Empty =>
209
210
" <?>"
210
211
case UnitConstant () =>
@@ -245,7 +246,6 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
245
246
s " private[ ${ssym}] "
246
247
case ProtectedWithinAccess (ssym) =>
247
248
s " protected[ ${ssym}] "
248
-
249
249
extension (scope : Scope )
250
250
private def infos : List [SymbolInformation ] =
251
251
if (scope.symlinks.nonEmpty)
@@ -258,8 +258,8 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
258
258
case Some (s) => s.infos
259
259
case None => Nil
260
260
}
261
- }
262
- end SymbolInfomationPrinter
261
+ end InfoPrinter
262
+ end SymbolInformationPrinter
263
263
264
264
extension (info : SymbolInformation )
265
265
def prefixBeforeTpe : String = {
@@ -280,3 +280,110 @@ object PrinterSymtab:
280
280
new PrinterSymtab {
281
281
override def info (symbol : String ): Option [SymbolInformation ] = map.get(symbol)
282
282
}
283
+
284
+ def processRange (sb : StringBuilder , range : Range ): Unit =
285
+ sb.append('[' )
286
+ .append(range.startLine).append(':' ).append(range.startCharacter)
287
+ .append(" .." )
288
+ .append(range.endLine).append(':' ).append(range.endCharacter)
289
+ .append(" ):" )
290
+
291
+
292
+
293
+ class SyntheticPrinter (symtab : PrinterSymtab , source : SourceFile ) extends SymbolInformationPrinter (symtab):
294
+
295
+ def pprint (synth : Synthetic ): String =
296
+ val sb = new StringBuilder ()
297
+ val notes = InfoNotes ()
298
+ val treePrinter = TreePrinter (source, synth.range, notes)
299
+
300
+ synth.range match
301
+ case Some (range) =>
302
+ processRange(sb, range)
303
+ sb.append(source.substring(range))
304
+ case None =>
305
+ sb.append(" [):" )
306
+ sb.append(" => " )
307
+ sb.append(treePrinter.pprint(synth.tree))
308
+ sb.toString
309
+
310
+ extension (source : SourceFile )
311
+ private def substring (range : Option [s.Range ]): String =
312
+ range match
313
+ case Some (range) => source.substring(range)
314
+ case None => " "
315
+ private def substring (range : s.Range ): String =
316
+ /** get the line length of a given line */
317
+ def lineLength (line : Int ): Int =
318
+ val isLastLine = source.lineToOffsetOpt(line).nonEmpty && source.lineToOffsetOpt(line + 1 ).isEmpty
319
+ if isLastLine then source.content.length - source.lineToOffset(line) - 1
320
+ else source.lineToOffset(line + 1 ) - source.lineToOffset(line) - 1 // -1 for newline char
321
+
322
+ val start = source.lineToOffset(range.startLine) +
323
+ math.min(range.startCharacter, lineLength(range.startLine))
324
+ val end = source.lineToOffset(range.endLine) +
325
+ math.min(range.endCharacter, lineLength(range.endLine))
326
+ new String (source.content, start, end - start)
327
+
328
+
329
+ // def pprint(tree: s.Tree, range: Option[Range]): String =
330
+ class TreePrinter (source : SourceFile , originalRange : Option [Range ], notes : InfoNotes ) extends InfoPrinter (notes):
331
+ def pprint (tree : Tree ): String =
332
+ val sb = new StringBuilder ()
333
+ processTree(tree)(using sb)
334
+ sb.toString
335
+
336
+
337
+ private def rep [T ](xs : Seq [T ], seq : String )(f : T => Unit )(using sb : StringBuilder ): Unit =
338
+ xs.zipWithIndex.foreach { (x, i) =>
339
+ if i != 0 then sb.append(seq)
340
+ f(x)
341
+ }
342
+
343
+ private def processTree (tree : Tree )(using sb : StringBuilder ): Unit =
344
+ tree match {
345
+ case tree : ApplyTree =>
346
+ processTree(tree.function)
347
+ sb.append(" (" )
348
+ rep(tree.arguments, " , " )(processTree)
349
+ sb.append(" )" )
350
+ case tree : FunctionTree =>
351
+ sb.append(" {" )
352
+ sb.append(" (" )
353
+ rep(tree.parameters, " , " )(processTree)
354
+ sb.append(" ) =>" )
355
+ processTree(tree.body)
356
+ sb.append(" }" )
357
+ case tree : IdTree =>
358
+ sb.append(pprintRef(tree.symbol))
359
+ case tree : LiteralTree =>
360
+ sb.append(pprint(tree.constant))
361
+ case tree : MacroExpansionTree =>
362
+ sb.append(" (`macro-expandee` : `" )
363
+ sb.append(pprint(tree.tpe))
364
+ sb.append(" )" )
365
+ case tree : OriginalTree =>
366
+ if (tree.range == originalRange && originalRange.nonEmpty) then
367
+ sb.append(" *" )
368
+ else
369
+ sb.append(" orig(" )
370
+ sb.append(source.substring(tree.range))
371
+ sb.append(" )" )
372
+ case tree : SelectTree =>
373
+ processTree(tree.qualifier)
374
+ sb.append(" ." )
375
+ tree.id match
376
+ case Some (tree) => processTree(tree)
377
+ case None => ()
378
+ case tree : TypeApplyTree =>
379
+ processTree(tree.function)
380
+ sb.append(" [" )
381
+ rep(tree.typeArguments, " , " )((t) => sb.append(pprint(t)))
382
+ sb.append(" ]" )
383
+
384
+ case _ =>
385
+ sb.append(" <?>" )
386
+ }
387
+
388
+
389
+ end SyntheticPrinter
0 commit comments