@@ -22,6 +22,8 @@ import scala.collection.mutable
22
22
import scala .annotation .{ threadUnsafe => tu , tailrec }
23
23
import scala .PartialFunction .condOpt
24
24
25
+ import SemanticSymbolBuilder ._
26
+ import SymbolInformationOps ._
25
27
26
28
/** Extract symbol references and uses to semanticdb files.
27
29
* See https://scalameta.org/docs/semanticdb/specification.html#symbol-1
@@ -49,18 +51,9 @@ class ExtractSemanticDB extends Phase:
49
51
/** Extractor of symbol occurrences from trees */
50
52
class Extractor extends TreeTraverser :
51
53
52
- private var nextLocalIdx : Int = 0
53
-
54
- /** The index of a local symbol */
55
- private val locals = mutable.HashMap [Symbol , Int ]()
56
-
57
54
/** The bodies of synthetic locals */
58
55
private val localBodies = mutable.HashMap [Symbol , Tree ]()
59
56
60
- /** The local symbol(s) starting at given offset */
61
- private val symsAtOffset = new mutable.HashMap [Int , Set [Symbol ]]():
62
- override def default (key : Int ) = Set [Symbol ]()
63
-
64
57
/** The extracted symbol occurrences */
65
58
val occurrences = new mutable.ListBuffer [SymbolOccurrence ]()
66
59
@@ -142,12 +135,12 @@ class ExtractSemanticDB extends Phase:
142
135
if ! tree.symbol.isAllOf(ModuleValCreationFlags ) then
143
136
if ! excludeDef(tree.symbol)
144
137
&& tree.span.hasLength then
145
- registerDefinition(tree.symbol, tree.nameSpan, symbolKinds( tree) , tree.source)
138
+ registerDefinition(tree.symbol, tree.nameSpan, tree.symbolKinds , tree.source)
146
139
val privateWithin = tree.symbol.privateWithin
147
140
if privateWithin.exists then
148
141
registerUseGuarded(None , privateWithin, spanOfSymbol(privateWithin, tree.span, tree.source), tree.source)
149
142
else if ! excludeSymbol(tree.symbol) then
150
- registerSymbol(tree.symbol, symbolName( tree.symbol), symbolKinds(tree) )
143
+ registerSymbol(tree.symbol, tree.symbolKinds)
151
144
tree match
152
145
case tree : ValDef
153
146
if tree.symbol.isAllOf(EnumValue ) =>
@@ -248,14 +241,6 @@ class ExtractSemanticDB extends Phase:
248
241
249
242
end traverse
250
243
251
- private def funParamSymbol (funSym : Symbol )(using Context ): Name => String =
252
- if funSym.isGlobal then
253
- val funSymbol = symbolName(funSym)
254
- name => s " $funSymbol( $name) "
255
- else
256
- name => locals.keys.find(local => local.isTerm && local.owner == funSym && local.name == name)
257
- .fold(" <?>" )(Symbols .LocalPrefix + _)
258
-
259
244
private object PatternValDef :
260
245
261
246
def unapply (tree : ValDef )(using Context ): Option [(Tree , Tree )] = tree.rhs match
@@ -289,185 +274,24 @@ class ExtractSemanticDB extends Phase:
289
274
290
275
end PatternValDef
291
276
292
- /** Add semanticdb name of the given symbol to string builder */
293
- private def addSymName (b : StringBuilder , sym : Symbol )(using Context ): Unit =
294
-
295
- def addName (name : Name ) =
296
- val str = name.toString.unescapeUnicode
297
- if str.isJavaIdent then b append str
298
- else b append '`' append str append '`'
299
-
300
- def addOwner (owner : Symbol ): Unit =
301
- if ! owner.isRoot then addSymName(b, owner)
302
-
303
- def addOverloadIdx (sym : Symbol ): Unit =
304
- val decls =
305
- val decls0 = sym.owner.info.decls.lookupAll(sym.name)
306
- if sym.owner.isAllOf(JavaModule ) then
307
- decls0 ++ sym.owner.companionClass.info.decls.lookupAll(sym.name)
308
- else
309
- decls0
310
- end decls
311
- val alts = decls.filter(_.isOneOf(Method | Mutable )).toList.reverse
312
- def find (filter : Symbol => Boolean ) = alts match
313
- case notSym :: rest if ! filter(notSym) =>
314
- val idx = rest.indexWhere(filter).ensuring(_ >= 0 )
315
- b.append('+' ).append(idx + 1 )
316
- case _ =>
317
- end find
318
- val sig = sym.signature
319
- find(_.signature == sig)
320
-
321
- def addDescriptor (sym : Symbol ): Unit =
322
- if sym.is(ModuleClass ) then
323
- addDescriptor(sym.sourceModule)
324
- else if sym.is(TypeParam ) then
325
- b.append('[' ); addName(sym.name); b.append(']' )
326
- else if sym.is(Param ) then
327
- b.append('(' ); addName(sym.name); b.append(')' )
328
- else if sym.isRoot then
329
- b.append(Symbols .RootPackage )
330
- else if sym.isEmptyPackage then
331
- b.append(Symbols .EmptyPackage )
332
- else if (sym.isScala2PackageObject) then
333
- b.append(Symbols .PackageObjectDescriptor )
334
- else
335
- addName(sym.name)
336
- if sym.is(Package ) then b.append('/' )
337
- else if sym.isType || sym.isAllOf(JavaModule ) then b.append('#' )
338
- else if sym.isOneOf(Method | Mutable )
339
- && (! sym.is(StableRealizable ) || sym.isConstructor) then
340
- b.append('(' ); addOverloadIdx(sym); b.append(" )." )
341
- else b.append('.' )
342
-
343
- /** The index of local symbol `sym`. Symbols with the same name and
344
- * the same starting position have the same index.
345
- */
346
- def localIdx (sym : Symbol )(using Context ): Int =
347
- val startPos =
348
- assert(sym.span.exists, s " $sym should have a span " )
349
- sym.span.start
350
- @ tailrec
351
- def computeLocalIdx (sym : Symbol ): Int = locals get sym match
352
- case Some (idx) => idx
353
- case None => symsAtOffset(startPos).find(_.name == sym.name) match
354
- case Some (other) => computeLocalIdx(other)
355
- case None =>
356
- val idx = nextLocalIdx
357
- nextLocalIdx += 1
358
- locals(sym) = idx
359
- symsAtOffset(startPos) += sym
360
- idx
361
- end computeLocalIdx
362
- computeLocalIdx(sym)
363
- end localIdx
364
-
365
- if sym.exists then
366
- if sym.isGlobal then
367
- addOwner(sym.owner); addDescriptor(sym)
368
- else
369
- b.append(Symbols .LocalPrefix ).append(localIdx(sym))
370
-
371
- end addSymName
372
-
373
- /** The semanticdb name of the given symbol */
374
- private def symbolName (sym : Symbol )(using Context ): String =
375
- val b = StringBuilder (20 )
376
- addSymName(b, sym)
377
- b.toString
378
277
379
278
private def range (span : Span , treeSource : SourceFile )(using Context ): Option [Range ] =
380
279
def lineCol (offset : Int ) = (treeSource.offsetToLine(offset), treeSource.column(offset))
381
280
val (startLine, startCol) = lineCol(span.start)
382
281
val (endLine, endCol) = lineCol(span.end)
383
282
Some (Range (startLine, startCol, endLine, endCol))
384
283
385
- private def symbolKind (sym : Symbol , symkinds : Set [SymbolKind ])(using Context ): SymbolInformation .Kind =
386
- if sym.isTypeParam then
387
- SymbolInformation .Kind .TYPE_PARAMETER
388
- else if sym.is(TermParam ) then
389
- SymbolInformation .Kind .PARAMETER
390
- else if sym.isTerm && sym.owner.isTerm then
391
- SymbolInformation .Kind .LOCAL
392
- else if sym.isInlineMethod || sym.is(Macro ) then
393
- SymbolInformation .Kind .MACRO
394
- else if sym.isConstructor then
395
- SymbolInformation .Kind .CONSTRUCTOR
396
- else if sym.isSelfSym then
397
- SymbolInformation .Kind .SELF_PARAMETER
398
- else if sym.isOneOf(Method ) || symkinds.exists(_.isVarOrVal) then
399
- SymbolInformation .Kind .METHOD
400
- else if sym.isPackageObject then
401
- SymbolInformation .Kind .PACKAGE_OBJECT
402
- else if sym.is(Module ) then
403
- SymbolInformation .Kind .OBJECT
404
- else if sym.is(Package ) then
405
- SymbolInformation .Kind .PACKAGE
406
- else if sym.isAllOf(JavaInterface ) then
407
- SymbolInformation .Kind .INTERFACE
408
- else if sym.is(Trait ) then
409
- SymbolInformation .Kind .TRAIT
410
- else if sym.isClass then
411
- SymbolInformation .Kind .CLASS
412
- else if sym.isType then
413
- SymbolInformation .Kind .TYPE
414
- else if sym.is(ParamAccessor ) then
415
- SymbolInformation .Kind .FIELD
416
- else
417
- SymbolInformation .Kind .UNKNOWN_KIND
418
-
419
- private def symbolProps (sym : Symbol , symkinds : Set [SymbolKind ])(using Context ): Int =
420
- if sym.is(ModuleClass ) then
421
- return symbolProps(sym.sourceModule, symkinds)
422
- var props = 0
423
- if sym.isPrimaryConstructor then
424
- props |= SymbolInformation .Property .PRIMARY .value
425
- if sym.is(Abstract ) || symkinds.contains(SymbolKind .Abstract ) then
426
- props |= SymbolInformation .Property .ABSTRACT .value
427
- if sym.is(Final ) then
428
- props |= SymbolInformation .Property .FINAL .value
429
- if sym.is(Sealed ) then
430
- props |= SymbolInformation .Property .SEALED .value
431
- if sym.isOneOf(GivenOrImplicit ) then
432
- props |= SymbolInformation .Property .IMPLICIT .value
433
- if sym.is(Lazy , butNot= Module ) then
434
- props |= SymbolInformation .Property .LAZY .value
435
- if sym.isAllOf(Case | Module ) || sym.is(CaseClass ) || sym.isAllOf(EnumCase ) then
436
- props |= SymbolInformation .Property .CASE .value
437
- if sym.is(Covariant ) then
438
- props |= SymbolInformation .Property .COVARIANT .value
439
- if sym.is(Contravariant ) then
440
- props |= SymbolInformation .Property .CONTRAVARIANT .value
441
- if sym.isAllOf(DefaultMethod | JavaDefined ) || sym.is(Accessor ) && sym.name.is(NameKinds .DefaultGetterName ) then
442
- props |= SymbolInformation .Property .DEFAULT .value
443
- if symkinds.exists(_.isVal) then
444
- props |= SymbolInformation .Property .VAL .value
445
- if symkinds.exists(_.isVar) then
446
- props |= SymbolInformation .Property .VAR .value
447
- if sym.is(JavaStatic ) then
448
- props |= SymbolInformation .Property .STATIC .value
449
- if sym.is(Enum ) then
450
- props |= SymbolInformation .Property .ENUM .value
451
- props
452
-
453
- private def symbolInfo (sym : Symbol , symbolName : String , symkinds : Set [SymbolKind ])(using Context ): SymbolInformation =
454
- SymbolInformation (
455
- symbol = symbolName,
456
- language = Language .SCALA ,
457
- kind = symbolKind(sym, symkinds),
458
- properties = symbolProps(sym, symkinds),
459
- displayName = Symbols .displaySymbol(sym)
460
- )
461
284
462
- private def registerSymbol (sym : Symbol , symbolName : String , symkinds : Set [SymbolKind ])(using Context ): Unit =
463
- val isLocal = symbolName.isLocal
464
- if ! isLocal || ! localNames.contains(symbolName) then
285
+ private def registerSymbol (sym : Symbol , symkinds : Set [SymbolKind ])(using Context ): Unit =
286
+ val sname = symbolName(sym)
287
+ val isLocal = sname.isLocal
288
+ if ! isLocal || ! localNames.contains(sname) then
465
289
if isLocal then
466
- localNames += symbolName
467
- symbolInfos += symbolInfo(sym, symbolName, symkinds)
290
+ localNames += sname
291
+ symbolInfos += sym. symbolInfo(symkinds)( using LinkMode . SymlinkChildren )
468
292
469
293
private def registerSymbolSimple (sym : Symbol )(using Context ): Unit =
470
- registerSymbol(sym, symbolName(sym), Set .empty)
294
+ registerSymbol(sym, Set .empty)
471
295
472
296
private def registerOccurrence (symbol : String , span : Span , role : SymbolOccurrence .Role , treeSource : SourceFile )(using Context ): Unit =
473
297
val occ = SymbolOccurrence (range(span, treeSource), symbol, role)
@@ -486,15 +310,15 @@ class ExtractSemanticDB extends Phase:
486
310
registerOccurrence(symbol, span, SymbolOccurrence .Role .REFERENCE , treeSource)
487
311
488
312
private def registerDefinition (sym : Symbol , span : Span , symkinds : Set [SymbolKind ], treeSource : SourceFile )(using Context ) =
489
- val symbol = symbolName(sym)
313
+ val sname = symbolName(sym)
490
314
val finalSpan = if ! span.hasLength || ! sym.is(Given ) || namePresentInSource(sym, span, treeSource) then
491
315
span
492
316
else
493
317
Span (span.start)
494
318
495
- registerOccurrence(symbol , finalSpan, SymbolOccurrence .Role .DEFINITION , treeSource)
319
+ registerOccurrence(sname , finalSpan, SymbolOccurrence .Role .DEFINITION , treeSource)
496
320
if ! sym.is(Package ) then
497
- registerSymbol(sym, symbol, symkinds)
321
+ registerSymbol(sym, symkinds)
498
322
499
323
private def namePresentInSource (sym : Symbol , span : Span , source: SourceFile )(using Context ): Boolean =
500
324
val content = source.content()
@@ -507,15 +331,6 @@ class ExtractSemanticDB extends Phase:
507
331
val start = if idx >= 0 then idx else span.start
508
332
Span (start, start + sym.name.show.length, start)
509
333
510
- extension (list : List [List [ValDef ]])
511
- private inline def isSingleArg = list match
512
- case (_:: Nil ):: Nil => true
513
- case _ => false
514
-
515
- extension (tree : DefDef )
516
- private def isSetterDef (using Context ): Boolean =
517
- tree.name.isSetterName && tree.mods.is(Accessor ) && tree.termParamss.isSingleArg
518
-
519
334
private def findGetters (ctorParams : Set [Names .TermName ], body : List [Tree ])(using Context ): Map [Names .TermName , ValDef ] =
520
335
if ctorParams.isEmpty || body.isEmpty then
521
336
Map .empty
@@ -562,28 +377,6 @@ class ExtractSemanticDB extends Phase:
562
377
private inline def matchingMemberType (ctorTypeParam : Symbol , classSym : Symbol )(using Context ) =
563
378
classSym.info.member(ctorTypeParam.name).symbol
564
379
565
- /** Necessary because not all of the eventual flags are propagated from the Tree to the symbol yet.
566
- */
567
- private def symbolKinds (tree : NamedDefTree )(using Context ): Set [SymbolKind ] =
568
- if tree.symbol.isSelfSym then
569
- Set .empty
570
- else
571
- val symkinds = mutable.HashSet .empty[SymbolKind ]
572
- tree match
573
- case tree : ValDef =>
574
- if ! tree.symbol.is(Param ) then
575
- symkinds += (if tree.mods is Mutable then SymbolKind .Var else SymbolKind .Val )
576
- if tree.rhs.isEmpty && ! tree.symbol.isOneOf(TermParam | CaseAccessor | ParamAccessor ) then
577
- symkinds += SymbolKind .Abstract
578
- case tree : DefDef =>
579
- if tree.isSetterDef then
580
- symkinds += SymbolKind .Setter
581
- else if tree.rhs.isEmpty then
582
- symkinds += SymbolKind .Abstract
583
- case tree : Bind =>
584
- symkinds += SymbolKind .Val
585
- case _ =>
586
- symkinds.toSet
587
380
588
381
private def ctorParams (
589
382
vparamss : List [List [ValDef ]], body : List [Tree ])(using Context ): Unit =
@@ -597,7 +390,7 @@ class ExtractSemanticDB extends Phase:
597
390
val symkinds =
598
391
getters.get(vparam.name).fold(SymbolKind .emptySet)(getter =>
599
392
if getter.mods.is(Mutable ) then SymbolKind .VarSet else SymbolKind .ValSet )
600
- registerSymbol(vparam.symbol, symbolName(vparam.symbol), symkinds)
393
+ registerSymbol(vparam.symbol, symkinds)
601
394
traverse(vparam.tpt)
602
395
603
396
object ExtractSemanticDB :
0 commit comments