Skip to content

Commit

Permalink
multiple-round: implement Resolver.getNewFiles()
Browse files Browse the repository at this point in the history
Also, do not create processors repeatedly in each round.
  • Loading branch information
ting-yuan committed Aug 16, 2023
1 parent 462cc54 commit e250af5
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import com.google.devtools.ksp.KSObjectCacheManager
import com.google.devtools.ksp.analysisapi.providers.IncrementalKotlinDeclarationProviderFactory
import com.google.devtools.ksp.analysisapi.providers.IncrementalKotlinPackageProviderFactory
import com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSFileJavaImpl
import com.google.devtools.ksp.impl.symbol.kotlin.analyze
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.processing.impl.CodeGeneratorImpl
import com.google.devtools.ksp.processing.impl.JvmPlatformInfoImpl
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSFile
import com.google.devtools.ksp.toKotlinVersion
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CorePackageIndex
Expand All @@ -43,6 +45,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiTreeChangeAdapter
import com.intellij.psi.PsiTreeChangeListener
Expand Down Expand Up @@ -118,6 +121,7 @@ import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile
import java.nio.file.Files
import java.nio.file.Paths

class KotlinSymbolProcessing(
Expand Down Expand Up @@ -355,13 +359,17 @@ class KotlinSymbolProcessing(
val kspCoreEnvironment = KSPCoreEnvironment(analysisAPISession.project as MockProject)

// TODO: deferred symbols: use PSIs; they don't change.
// TODO: KSFiles for java
// TODO: error handling, onError()
// TODO: Resolver.getNewFiles()
// TODO: performance
val project = analysisAPISession.project
val psiManager = PsiManager.getInstance(project)
var finished = false
var initialized = false
lateinit var codeGenerator: CodeGeneratorImpl
lateinit var processors: List<SymbolProcessor>
lateinit var newKSFiles: List<KSFile>
lateinit var newFileNames: Set<String>
while (!finished) {
val project = analysisAPISession.project
val ktFiles = createSourceFilesFromSourceRoots(
compilerConfiguration, analysisAPISession.project, compilerConfiguration.kotlinSourceRoots
).toSet().toList()
Expand All @@ -386,42 +394,62 @@ class KotlinSymbolProcessing(
reinitJavaFileManager(kotlinCoreProjectEnvironment, modules, psiFiles)

ResolverAAImpl.ktModule = modules.single()
val ksFiles = ktFiles.map { file ->
analyze { KSFileImpl.getCached(file.getFileSymbol()) }
}
val anyChangesWildcard = AnyChanges(kspConfig.projectBaseDir)
val codeGenerator = CodeGeneratorImpl(
kspConfig.classOutputDir,
{ kspConfig.javaOutputDir },
kspConfig.kotlinOutputDir,
kspConfig.resourceOutputDir,
kspConfig.projectBaseDir,
anyChangesWildcard,
ksFiles,
kspConfig.incremental
)
val processors = providers.mapNotNull { provider ->
var processor: SymbolProcessor? = null
processor = provider.create(
SymbolProcessorEnvironment(
kspConfig.processorOptions,
kspConfig.languageVersion.toKotlinVersion(),
codeGenerator,
kspConfig.logger,
kspConfig.apiVersion.toKotlinVersion(),
// TODO: compilerVersion
KotlinVersion.CURRENT,
// TODO: fix platform info
listOf(JvmPlatformInfoImpl("JVM", "1.8", "disable"))
)
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
val javaRoots = kspConfig.javaSourceRoots + kspConfig.javaOutputDir
// Get non-symbolic paths first
val javaFiles = javaRoots.sortedBy { Files.isSymbolicLink(it.toPath()) }
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
// This time is for .java files
.sortedBy { Files.isSymbolicLink(it.toPath()) }
.distinctBy { it.canonicalPath }
.mapNotNull { localFileSystem.findFileByPath(it.path)?.let { psiManager.findFile(it) } as? PsiJavaFile }

val allKSFiles =
ktFiles.map { analyze { KSFileImpl.getCached(it.getFileSymbol()) } } +
javaFiles.map { KSFileJavaImpl.getCached(it) }
if (!initialized) {
val anyChangesWildcard = AnyChanges(kspConfig.projectBaseDir)
codeGenerator = CodeGeneratorImpl(
kspConfig.classOutputDir,
{ kspConfig.javaOutputDir },
kspConfig.kotlinOutputDir,
kspConfig.resourceOutputDir,
kspConfig.projectBaseDir,
anyChangesWildcard,
allKSFiles,
kspConfig.incremental
)
processor.also { deferredSymbols[it] = mutableListOf() }

processors = providers.mapNotNull { provider ->
var processor: SymbolProcessor? = null
processor = provider.create(
SymbolProcessorEnvironment(
kspConfig.processorOptions,
kspConfig.languageVersion.toKotlinVersion(),
codeGenerator,
kspConfig.logger,
kspConfig.apiVersion.toKotlinVersion(),
// TODO: compilerVersion
KotlinVersion.CURRENT,
// TODO: fix platform info
listOf(JvmPlatformInfoImpl("JVM", "1.8", "disable"))
)
)
processor.also { deferredSymbols[it] = mutableListOf() }
}

newKSFiles = allKSFiles

initialized = true
} else {
newKSFiles = allKSFiles.filter {
it.filePath in newFileNames
}
}
// TODO: support no kotlin source input.
val resolver = ResolverAAImpl(
ktFiles.map {
analyze { it.getFileSymbol() }
},
allKSFiles,
newKSFiles,
kspConfig,
analysisAPISession.project
)
Expand All @@ -438,12 +466,13 @@ class KotlinSymbolProcessing(
KotlinModificationTrackerFactory.getService(project)
.incrementModificationsCount(includeBinaryTrackers = false)
KtAnalysisSessionProvider.getInstance(project).clearCaches()
project.getService(KotlinModificationTrackerFactory::class.java)
.incrementModificationsCount(false)
PsiManager.getInstance(project).dropResolveCaches()
PsiManager.getInstance(project).dropPsiCaches()
psiManager.dropResolveCaches()
psiManager.dropPsiCaches()

KSObjectCacheManager.clear()

newFileNames = codeGenerator.generatedFile.filter { it.extension == "kt" || it.extension == "java" }
.map { it.canonicalPath }.toSet()
}

codeGenerator.closeFiles()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.hasAnnotation
import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationEnumEntryImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSFileJavaImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSFunctionDeclarationImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSPropertyAccessorImpl
import com.google.devtools.ksp.impl.symbol.kotlin.KSPropertyDeclarationImpl
Expand All @@ -60,15 +58,10 @@ import com.google.devtools.ksp.symbol.*
import com.google.devtools.ksp.toKSName
import com.google.devtools.ksp.visitor.CollectAnnotatedSymbolsVisitor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.file.impl.JavaFileManager
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtJavaFieldSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
Expand All @@ -87,11 +80,11 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.org.objectweb.asm.Opcodes
import java.nio.file.Files

@OptIn(KspExperimental::class)
class ResolverAAImpl(
val ktFiles: List<KtFileSymbol>,
val allKSFiles: List<KSFile>,
val newKSFiles: List<KSFile>,
val kspConfig: KSPJvmConfig,
val project: Project
) : Resolver {
Expand All @@ -100,23 +93,7 @@ class ResolverAAImpl(
lateinit var ktModule: KtModule
}

val javaFiles: List<PsiJavaFile>
val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
init {
val psiManager = PsiManager.getInstance(project)
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
// Get non-symbolic paths first
javaFiles = kspConfig.javaSourceRoots.sortedBy { Files.isSymbolicLink(it.toPath()) }
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
// This time is for .java files
.sortedBy { Files.isSymbolicLink(it.toPath()) }
.distinctBy { it.canonicalPath }
.mapNotNull { localFileSystem.findFileByPath(it.path)?.let { psiManager.findFile(it) } as? PsiJavaFile }
}

private val ksFiles by lazy {
ktFiles.map { KSFileImpl.getCached(it) } + javaFiles.map { KSFileJavaImpl.getCached(it) }
}

// TODO: fix in upstream for builtin types.
override val builtIns: KSBuiltIns by lazy {
Expand Down Expand Up @@ -264,7 +241,7 @@ class ResolverAAImpl(
}

override fun getAllFiles(): Sequence<KSFile> {
return ksFiles.asSequence()
return allKSFiles.asSequence()
}

override fun getClassDeclarationByName(name: KSName): KSClassDeclaration? {
Expand Down Expand Up @@ -411,7 +388,7 @@ class ResolverAAImpl(

// FIXME: correct implementation after incremental is ready.
override fun getNewFiles(): Sequence<KSFile> {
return getAllFiles().asSequence()
return newKSFiles.asSequence()
}

override fun getOwnerJvmClassName(declaration: KSFunctionDeclaration): String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class MultipleroundProcessor : AbstractTestProcessor() {
result.add("Round $round:")
check("K")
check("J")
val newFiles = resolver.getNewFiles().map { it.fileName }.toSet()
val allFiles = resolver.getAllFiles().map { it.fileName }
result.add(allFiles.map { if (it in newFiles) "+$it" else it }.sorted().joinToString())

round++
return emptyList()
Expand Down
7 changes: 7 additions & 0 deletions test-utils/testData/api/multipleround.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,31 @@
// Round 0:
// K : <Error>, <Error>, <Error>, <Error>, <Error>, <Error>
// J : <Error>, <Error>, <Error>, <Error>, <Error>, <Error>
// +J.java, +K.kt
// Round 1:
// K : I0, <Error>, <Error>, <Error>, <Error>, <Error>
// J : I0, <Error>, <Error>, <Error>, <Error>, <Error>
// +I0.kt, J.java, K.kt
// Round 2:
// K : I0, I1, <Error>, <Error>, <Error>, <Error>
// J : I0, I1, <Error>, <Error>, <Error>, <Error>
// +I1.java, I0.kt, J.java, K.kt
// Round 3:
// K : I0, I1, I2, <Error>, <Error>, <Error>
// J : I0, I1, I2, <Error>, <Error>, <Error>
// +I2.kt, I0.kt, I1.java, J.java, K.kt
// Round 4:
// K : I0, I1, I2, I3, <Error>, <Error>
// J : I0, I1, I2, I3, <Error>, <Error>
// +I3.java, I0.kt, I1.java, I2.kt, J.java, K.kt
// Round 5:
// K : I0, I1, I2, I3, I4, <Error>
// J : I0, I1, I2, I3, I4, <Error>
// +I4.kt, I0.kt, I1.java, I2.kt, I3.java, J.java, K.kt
// Round 6:
// K : I0, I1, I2, I3, I4, I5
// J : I0, I1, I2, I3, I4, I5
// +I5.java, I0.kt, I1.java, I2.kt, I3.java, I4.kt, J.java, K.kt
// END

// FILE: K.kt
Expand Down

0 comments on commit e250af5

Please sign in to comment.