Skip to content

Commit 01db07a

Browse files
nicolas-guichardantonsviridov-src
authored andcommitted
Package and import support
We need to support the package directive and the imports so that: - `package a.b.c` has 3 symbol occurences, for `a/`, `a/b/` and `a/b/c/` - `import a.b.Klass` has 3 symbol occurences, for `a/`, `a/b/` and `a/b/Klass#` Still 5 failing tests.
1 parent c134ab6 commit 01db07a

File tree

4 files changed

+103
-16
lines changed

4 files changed

+103
-16
lines changed

semanticdb-kotlinc/src/main/kotlin/com/sourcegraph/semanticdb_kotlinc/AnalyzerCheckers.kt

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ package com.sourcegraph.semanticdb_kotlinc
22

33
import java.nio.file.Path
44
import kotlin.contracts.ExperimentalContracts
5-
import org.jetbrains.kotlin.KtSourceElement
6-
import org.jetbrains.kotlin.KtSourceFile
5+
import org.jetbrains.kotlin.*
6+
import org.jetbrains.kotlin.com.intellij.lang.LighterASTNode
7+
import org.jetbrains.kotlin.com.intellij.util.diff.FlyweightCapableTreeStructure
78
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
9+
import org.jetbrains.kotlin.diagnostics.collectDescendantsOfType
810
import org.jetbrains.kotlin.diagnostics.findChildByType
11+
import org.jetbrains.kotlin.diagnostics.findLastDescendant
912
import org.jetbrains.kotlin.fir.FirSession
1013
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
1114
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
@@ -20,7 +23,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
2023
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
2124
import org.jetbrains.kotlin.lexer.KtTokens
2225
import org.jetbrains.kotlin.name.ClassId
23-
import org.jetbrains.kotlin.toKtLightSourceElement
26+
import org.jetbrains.kotlin.name.FqName
2427

2528
open class AnalyzerCheckers(session: FirSession) : FirAdditionalCheckersExtension(session) {
2629
companion object {
@@ -92,15 +95,69 @@ open class AnalyzerCheckers(session: FirSession) : FirAdditionalCheckersExtensio
9295
reporter: DiagnosticReporter
9396
) {
9497
val ktFile = declaration.sourceFile ?: return
98+
val visitor = visitors[ktFile]
99+
100+
val eachFqNameElement =
101+
{
102+
fqName: FqName,
103+
tree: FlyweightCapableTreeStructure<LighterASTNode>,
104+
names: LighterASTNode,
105+
callback: (FqName, KtLightSourceElement) -> Unit ->
106+
val nameList =
107+
if (names.tokenType == KtNodeTypes.REFERENCE_EXPRESSION) listOf(names)
108+
else tree.collectDescendantsOfType(names, KtNodeTypes.REFERENCE_EXPRESSION)
109+
110+
var ancestor = fqName
111+
var depth = 0
112+
while (ancestor != FqName.ROOT) {
113+
val nameNode = nameList[nameList.lastIndex - depth]
114+
val nameSource = nameNode.toKtLightSourceElement(tree)
115+
116+
callback(ancestor, nameSource)
117+
118+
ancestor = ancestor.parent()
119+
depth++
120+
}
121+
}
122+
123+
val packageDirective = declaration.packageDirective
124+
val fqName = packageDirective.packageFqName
125+
val source = packageDirective.source
126+
if (source != null) {
127+
val names = source.treeStructure.findLastDescendant(source.lighterASTNode) { true }
128+
if (names != null) {
129+
eachFqNameElement(fqName, source.treeStructure, names) { fqName, name ->
130+
visitor?.visitPackage(fqName, name)
131+
}
132+
}
133+
}
134+
95135
declaration.imports.forEach { import ->
96136
val source = import.source ?: return@forEach
97-
val visitor = visitors[ktFile]
98137
val fqName = import.importedFqName ?: return@forEach
99-
val importedClassSymbol =
100-
context.session.symbolProvider.getClassLikeSymbolByClassId(
101-
ClassId.topLevel(fqName))
102-
?: return@forEach
103-
visitor?.visitImport(importedClassSymbol, source)
138+
139+
val names = source.treeStructure.findLastDescendant(source.lighterASTNode) { true }
140+
if (names != null) {
141+
eachFqNameElement(fqName, source.treeStructure, names) { fqName, name ->
142+
val symbolProvider = context.session.symbolProvider
143+
144+
val klass =
145+
symbolProvider.getClassLikeSymbolByClassId(ClassId.topLevel(fqName))
146+
val callables =
147+
symbolProvider.getTopLevelCallableSymbols(
148+
fqName.parent(), fqName.shortName())
149+
150+
if (klass != null) {
151+
visitor?.visitClassReference(klass, name)
152+
} else if (callables.isNotEmpty()) {
153+
for (callable in callables) {
154+
visitor?.visitCallableReference(callable, name)
155+
}
156+
} else {
157+
visitor?.visitPackage(fqName, name)
158+
}
159+
}
160+
}
104161
}
105162
}
106163
}

semanticdb-kotlinc/src/main/kotlin/com/sourcegraph/semanticdb_kotlinc/SemanticdbTextDocumentBuilder.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class SemanticdbTextDocumentBuilder(
4242
}
4343

4444
fun emitSemanticdbData(
45-
firBasedSymbol: FirBasedSymbol<*>,
45+
firBasedSymbol: FirBasedSymbol<*>?,
4646
symbol: Symbol,
4747
element: KtSourceElement,
4848
role: Role
@@ -62,7 +62,7 @@ class SemanticdbTextDocumentBuilder(
6262

6363
@OptIn(SymbolInternals::class)
6464
private fun symbolInformation(
65-
firBasedSymbol: FirBasedSymbol<*>,
65+
firBasedSymbol: FirBasedSymbol<*>?,
6666
symbol: Symbol,
6767
element: KtSourceElement
6868
): Semanticdb.SymbolInformation {
@@ -81,8 +81,21 @@ class SemanticdbTextDocumentBuilder(
8181
}
8282
return SymbolInformation {
8383
this.symbol = symbol.toString()
84-
this.displayName = displayName(firBasedSymbol)
85-
this.documentation = semanticdbDocumentation(firBasedSymbol.fir)
84+
this.displayName =
85+
if (firBasedSymbol != null) {
86+
displayName(firBasedSymbol)
87+
} else {
88+
element.text.toString()
89+
}
90+
this.documentation =
91+
if (firBasedSymbol != null) {
92+
semanticdbDocumentation(firBasedSymbol.fir)
93+
} else {
94+
Documentation {
95+
format = Semanticdb.Documentation.Format.MARKDOWN
96+
message = ""
97+
}
98+
}
8699
this.addAllOverriddenSymbols(supers)
87100
this.language =
88101
when (element.psi?.language ?: KotlinLanguage.INSTANCE) {

semanticdb-kotlinc/src/main/kotlin/com/sourcegraph/semanticdb_kotlinc/SemanticdbVisitor.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import org.jetbrains.kotlin.KtSourceFile
88
import org.jetbrains.kotlin.fir.declarations.*
99
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
1010
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
11+
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
1112
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
13+
import org.jetbrains.kotlin.name.FqName
1214

1315
@ExperimentalContracts
1416
class SemanticdbVisitor(
@@ -22,7 +24,7 @@ class SemanticdbVisitor(
2224
private val documentBuilder = SemanticdbTextDocumentBuilder(sourceroot, file, lineMap)
2325

2426
private data class SymbolDescriptorPair(
25-
val firBasedSymbol: FirBasedSymbol<*>,
27+
val firBasedSymbol: FirBasedSymbol<*>?,
2628
val symbol: Symbol
2729
)
2830

@@ -40,10 +42,18 @@ class SemanticdbVisitor(
4042
?.map { it.symbol }
4143
?.toList()
4244

43-
private fun Sequence<Symbol>.with(firBasedSymbol: FirBasedSymbol<*>) =
45+
private fun Sequence<Symbol>.with(firBasedSymbol: FirBasedSymbol<*>?) =
4446
this.map { SymbolDescriptorPair(firBasedSymbol, it) }
4547

46-
fun visitImport(firClassSymbol: FirClassLikeSymbol<*>, element: KtSourceElement) {
48+
fun visitPackage(pkg: FqName, element: KtSourceElement) {
49+
cache[pkg].with(null).emitAll(element, Role.REFERENCE)
50+
}
51+
52+
fun visitClassReference(firClassSymbol: FirClassLikeSymbol<*>, element: KtSourceElement) {
53+
cache[firClassSymbol].with(firClassSymbol).emitAll(element, Role.REFERENCE)
54+
}
55+
56+
fun visitCallableReference(firClassSymbol: FirCallableSymbol<*>, element: KtSourceElement) {
4757
cache[firClassSymbol].with(firClassSymbol).emitAll(element, Role.REFERENCE)
4858
}
4959

semanticdb-kotlinc/src/main/kotlin/com/sourcegraph/semanticdb_kotlinc/SymbolsCache.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class GlobalSymbolsCache(testing: Boolean = false) : Iterable<Symbol> {
3131
emitSymbols(symbol, locals)
3232
}
3333

34+
operator fun get(symbol: FqName): Sequence<Symbol> = sequence { emitSymbols(symbol) }
35+
3436
/**
3537
* called whenever a new symbol should be yielded in the sequence e.g. for properties we also
3638
* want to yield for every implicit getter/setter, but wouldn't want to yield for e.g. the
@@ -50,6 +52,10 @@ class GlobalSymbolsCache(testing: Boolean = false) : Iterable<Symbol> {
5052
}
5153
}
5254

55+
private suspend fun SequenceScope<Symbol>.emitSymbols(symbol: FqName) {
56+
yield(getSymbol(symbol))
57+
}
58+
5359
/**
5460
* Entrypoint for building or looking-up a symbol without yielding a value in the sequence.
5561
* Called recursively for every part of a symbol, unless a cached result short circuits.
@@ -220,4 +226,5 @@ class LocalSymbolsCache : Iterable<Symbol> {
220226
@ExperimentalContracts
221227
class SymbolsCache(private val globals: GlobalSymbolsCache, private val locals: LocalSymbolsCache) {
222228
operator fun get(symbol: FirBasedSymbol<*>) = globals[symbol, locals]
229+
operator fun get(symbol: FqName) = globals[symbol]
223230
}

0 commit comments

Comments
 (0)