Repository: detekt/detekt (kotlin)

Issue:
Eliminate direct usage of KotlinCoreEnvironment
## Expected Behavior
detekt doesn't use KotlinCoreEnvironment directly.

## Current Behavior
This is passed around liberally within detekt.

## Context
This becomes a problem with the Analysis API. Analysis sessions are created by using a `StandaloneAnalysisAPISession` which uses KotlinCoreEnvironment internally to set up the analysis environment but it is not exposed anywhere.

Within detekt this is mostly used as a container for passing around `Project` and `CompilerConfiguration`. This can be done in other ways. `CompilerConfiguration` is created by detekt and can be used as an input into the analysis session as needed.

detekt should only use `Project` from the `StandaloneAnalysisAPISession`.

https://github.com/JetBrains/kotlin/blob/658a2010b15a22583f9841e1a2d4bddf1baac612/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISession.kt

Pull request:
Part of #8059

Patch:
diff --git a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/tooling/ParsingStrategy.kt b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/tooling/ParsingStrategy.kt
index 47cd3342eba7..4a5c621dbde1 100644
--- a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/tooling/ParsingStrategy.kt
+++ b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/tooling/ParsingStrategy.kt
@@ -7,7 +7,7 @@ import org.jetbrains.kotlin.psi.KtFile
 typealias ParsingStrategy = (settings: ProcessingSettings) -> List<KtFile>
 
 val inputPathsToKtFiles: ParsingStrategy = { settings ->
-    val compiler = KtCompiler(settings.environment)
+    val compiler = KtCompiler(settings.environment.project)
     settings.spec.projectSpec.inputPaths.map { path ->
         compiler.compile(path)
     }
diff --git a/detekt-parser/src/main/kotlin/io/github/detekt/parser/KtCompiler.kt b/detekt-parser/src/main/kotlin/io/github/detekt/parser/KtCompiler.kt
index b72525853f01..44255cf41c3f 100644
--- a/detekt-parser/src/main/kotlin/io/github/detekt/parser/KtCompiler.kt
+++ b/detekt-parser/src/main/kotlin/io/github/detekt/parser/KtCompiler.kt
@@ -1,21 +1,41 @@
 package io.github.detekt.parser
 
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.pom.PomModel
 import com.intellij.psi.util.PsiUtilCore
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
+import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
+import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
+import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
 import org.jetbrains.kotlin.psi.KtFile
 import java.nio.file.Path
 import kotlin.io.path.isRegularFile
 
 open class KtCompiler(
-    protected val environment: KotlinCoreEnvironment = createKotlinCoreEnvironment(printStream = System.err),
+    protected val project: Project = createDefaultAnalysisAPISession.project,
 ) {
 
     fun compile(path: Path): KtFile {
         require(path.isRegularFile()) { "Given path '$path' should be a regular file!" }
 
-        val virtualFile = requireNotNull(environment.findLocalFile(path.toString()))
-        return requireNotNull(PsiUtilCore.getPsiFile(environment.project, virtualFile) as? KtFile) {
+        val virtualFile = requireNotNull(VirtualFileManager.getInstance().findFileByNioPath(path)) {
+            "$path cannot be retrieved as a VirtualFile"
+        }
+
+        return requireNotNull(PsiUtilCore.getPsiFile(project, virtualFile) as? KtFile) {
             "$path is not a Kotlin file"
         }
     }
 }
+
+private val createDefaultAnalysisAPISession = buildStandaloneAnalysisAPISession {
+    registerProjectService(PomModel::class.java, DetektPomModel)
+
+    // Required until BindingContext usage is fully removed
+    registerProjectService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(true))
+
+    buildKtModuleProvider {
+        platform = JvmPlatforms.defaultJvmPlatform
+    }
+}


Test patch:
diff --git a/detekt-test-utils/src/main/kotlin/io/github/detekt/test/utils/KtTestCompiler.kt b/detekt-test-utils/src/main/kotlin/io/github/detekt/test/utils/KtTestCompiler.kt
index 50ed2b234b06..ed56728cea70 100644
--- a/detekt-test-utils/src/main/kotlin/io/github/detekt/test/utils/KtTestCompiler.kt
+++ b/detekt-test-utils/src/main/kotlin/io/github/detekt/test/utils/KtTestCompiler.kt
@@ -27,7 +27,7 @@ import kotlin.io.path.name
  */
 internal object KtTestCompiler : KtCompiler() {
 
-    private val psiFileFactory = KtPsiFactory(environment.project, markGenerated = false)
+    private val psiFileFactory = KtPsiFactory(project, markGenerated = false)
 
     /**
      * Not sure why but this function only works from this context.