-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SONARKT-400 Integrate kotlin-analysis-api
- Loading branch information
Showing
109 changed files
with
674 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K1.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* SonarSource Kotlin | ||
* Copyright (C) 2018-2024 SonarSource SA | ||
* mailto:info AT sonarsource DOT com | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
* See the Sonar Source-Available License for more details. | ||
* | ||
* You should have received a copy of the Sonar Source-Available License | ||
* along with this program; if not, see https://sonarsource.com/license/ssal/ | ||
*/ | ||
package org.sonarsource.kotlin.api.frontend | ||
|
||
import com.intellij.core.CoreApplicationEnvironment | ||
import com.intellij.mock.MockApplication | ||
import com.intellij.mock.MockProject | ||
import com.intellij.openapi.Disposable | ||
import com.intellij.psi.ClassTypePointerFactory | ||
import com.intellij.psi.impl.smartPointers.PsiClassReferenceTypePointerFactory | ||
import org.jetbrains.kotlin.analysis.api.KaAnalysisNonPublicApi | ||
import org.jetbrains.kotlin.analysis.api.descriptors.CliFe10AnalysisFacade | ||
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade | ||
import org.jetbrains.kotlin.analysis.api.descriptors.KaFe10AnalysisHandlerExtension | ||
import org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeTokenProvider | ||
import org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinLifetimeTokenProvider | ||
import org.jetbrains.kotlin.analysis.api.platform.modification.KotlinGlobalModificationService | ||
import org.jetbrains.kotlin.analysis.api.platform.modification.KotlinModificationTrackerFactory | ||
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinByModulesResolutionScopeProvider | ||
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinProjectStructureProvider | ||
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinResolutionScopeProvider | ||
import org.jetbrains.kotlin.analysis.api.standalone.base.modification.KotlinStandaloneGlobalModificationService | ||
import org.jetbrains.kotlin.analysis.api.standalone.base.modification.KotlinStandaloneModificationTrackerFactory | ||
import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.AnalysisApiSimpleServiceRegistrar | ||
import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.PluginStructureProvider | ||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment | ||
import org.jetbrains.kotlin.references.fe10.base.DummyKtFe10ReferenceResolutionHelper | ||
import org.jetbrains.kotlin.references.fe10.base.KtFe10ReferenceResolutionHelper | ||
import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension | ||
|
||
/** | ||
* Marker indicating that | ||
* annotated [org.sonarsource.kotlin.api.checks.KotlinCheck] | ||
* can be executed only in K1 mode. | ||
*/ | ||
annotation class K1only | ||
|
||
internal fun configureK1AnalysisApiServices(env: KotlinCoreEnvironment) { | ||
val application = env.projectEnvironment.environment.application | ||
if (application.getServiceIfCreated(KtFe10ReferenceResolutionHelper::class.java) == null) { | ||
AnalysisApiFe10ServiceRegistrar.registerApplicationServices(application) | ||
} | ||
val project = env.projectEnvironment.project | ||
AnalysisApiFe10ServiceRegistrar.registerProjectServices(project) | ||
AnalysisApiFe10ServiceRegistrar.registerProjectModelServices( | ||
project, | ||
env.projectEnvironment.parentDisposable | ||
) | ||
|
||
project.registerService( | ||
KotlinModificationTrackerFactory::class.java, | ||
KotlinStandaloneModificationTrackerFactory::class.java, | ||
) | ||
project.registerService( | ||
KotlinGlobalModificationService::class.java, | ||
KotlinStandaloneGlobalModificationService::class.java, | ||
) | ||
project.registerService( | ||
KotlinLifetimeTokenProvider::class.java, | ||
KotlinAlwaysAccessibleLifetimeTokenProvider::class.java, | ||
) | ||
project.registerService( | ||
KotlinResolutionScopeProvider::class.java, | ||
KotlinByModulesResolutionScopeProvider::class.java, | ||
); | ||
project.registerService( | ||
KotlinProjectStructureProvider::class.java, | ||
KtModuleProviderByCompilerConfiguration.build( | ||
env.projectEnvironment, | ||
env.configuration, | ||
listOf() | ||
) | ||
) | ||
} | ||
|
||
@OptIn(KaAnalysisNonPublicApi::class) | ||
private object AnalysisApiFe10ServiceRegistrar : AnalysisApiSimpleServiceRegistrar() { | ||
private const val PLUGIN_RELATIVE_PATH = "/META-INF/analysis-api/analysis-api-fe10.xml" | ||
|
||
override fun registerApplicationServices(application: MockApplication) { | ||
PluginStructureProvider.registerApplicationServices(application, PLUGIN_RELATIVE_PATH) | ||
application.registerService( | ||
KtFe10ReferenceResolutionHelper::class.java, | ||
DummyKtFe10ReferenceResolutionHelper, | ||
) | ||
val applicationArea = application.extensionArea | ||
if (!applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) { | ||
CoreApplicationEnvironment.registerApplicationExtensionPoint( | ||
ClassTypePointerFactory.EP_NAME, | ||
ClassTypePointerFactory::class.java, | ||
) | ||
applicationArea | ||
.getExtensionPoint(ClassTypePointerFactory.EP_NAME) | ||
.registerExtension(PsiClassReferenceTypePointerFactory(), application) | ||
} | ||
} | ||
|
||
override fun registerProjectExtensionPoints(project: MockProject) { | ||
AnalysisHandlerExtension.registerExtensionPoint(project) | ||
PluginStructureProvider.registerProjectExtensionPoints(project, PLUGIN_RELATIVE_PATH) | ||
} | ||
|
||
override fun registerProjectServices(project: MockProject) { | ||
PluginStructureProvider.registerProjectServices(project, PLUGIN_RELATIVE_PATH) | ||
PluginStructureProvider.registerProjectListeners(project, PLUGIN_RELATIVE_PATH) | ||
} | ||
|
||
override fun registerProjectModelServices(project: MockProject, disposable: Disposable) { | ||
project.apply { registerService(Fe10AnalysisFacade::class.java, CliFe10AnalysisFacade()) } | ||
AnalysisHandlerExtension.registerExtension(project, KaFe10AnalysisHandlerExtension()) | ||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K2.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* SonarSource Kotlin | ||
* Copyright (C) 2018-2024 SonarSource SA | ||
* mailto:info AT sonarsource DOT com | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
* See the Sonar Source-Available License for more details. | ||
* | ||
* You should have received a copy of the Sonar Source-Available License | ||
* along with this program; if not, see https://sonarsource.com/license/ssal/ | ||
*/ | ||
package org.sonarsource.kotlin.api.frontend | ||
|
||
import com.intellij.openapi.Disposable | ||
import com.intellij.openapi.util.io.FileUtil | ||
import com.intellij.openapi.vfs.VirtualFile | ||
import com.intellij.openapi.vfs.VirtualFileSystem | ||
import com.intellij.openapi.vfs.local.CoreLocalFileSystem | ||
import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession | ||
import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession | ||
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule | ||
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule | ||
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule | ||
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl | ||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots | ||
import org.jetbrains.kotlin.config.CompilerConfiguration | ||
import org.jetbrains.kotlin.config.JVMConfigurationKeys | ||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager | ||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms | ||
import java.io.File | ||
import java.io.InputStream | ||
import java.io.OutputStream | ||
|
||
/** | ||
* @see [org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISessionBuilder.buildKtModuleProviderByCompilerConfiguration] | ||
*/ | ||
fun createK2AnalysisSession( | ||
parentDisposable: Disposable, | ||
compilerConfiguration: CompilerConfiguration, | ||
virtualFiles: Collection<VirtualFile>, | ||
): StandaloneAnalysisAPISession { | ||
return buildStandaloneAnalysisAPISession( | ||
projectDisposable = parentDisposable, | ||
) { | ||
// https://github.com/JetBrains/kotlin/blob/a9ff22693479cabd201909a06e6764c00eddbf7b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/fe10/test/configurator/AnalysisApiFe10TestServiceRegistrar.kt#L49 | ||
registerProjectService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(enabled = true)) | ||
|
||
// TODO language version, jvm target, etc | ||
val platform = JvmPlatforms.defaultJvmPlatform | ||
buildKtModuleProvider { | ||
this.platform = platform | ||
addModule(buildKtSourceModule { | ||
this.platform = platform | ||
moduleName = "module" | ||
addSourceVirtualFiles(virtualFiles) | ||
addRegularDependency(buildKtLibraryModule { | ||
this.platform = platform | ||
libraryName = "library" | ||
addBinaryRoots(compilerConfiguration.jvmClasspathRoots.map { it.toPath() }) | ||
}) | ||
compilerConfiguration[JVMConfigurationKeys.JDK_HOME]?.let { jdkHome -> | ||
addRegularDependency(buildKtSdkModule { | ||
this.platform = platform | ||
addBinaryRootsFromJdkHome(jdkHome.toPath(), isJre = false) | ||
libraryName = "JDK" | ||
}) | ||
} | ||
}) | ||
} | ||
} | ||
} | ||
|
||
class KotlinFileSystem : CoreLocalFileSystem() { | ||
/** | ||
* TODO return null if file does not exist - see [CoreLocalFileSystem.findFileByNioFile] | ||
*/ | ||
override fun findFileByPath(path: String): VirtualFile? = | ||
KotlinVirtualFile(this, File(path)) | ||
} | ||
|
||
class KotlinVirtualFile( | ||
private val fileSystem: KotlinFileSystem, | ||
private val file: File, | ||
private val content: String? = null, | ||
) : VirtualFile() { | ||
|
||
override fun getName(): String = file.name | ||
|
||
override fun getFileSystem(): VirtualFileSystem = fileSystem | ||
|
||
override fun getPath(): String = FileUtil.toSystemIndependentName(file.absolutePath) | ||
|
||
override fun isWritable(): Boolean = false | ||
|
||
override fun isDirectory(): Boolean = file.isDirectory | ||
|
||
override fun isValid(): Boolean = true | ||
|
||
override fun getParent(): VirtualFile? { | ||
val parentFile = file.parentFile ?: return null | ||
return KotlinVirtualFile(fileSystem, parentFile) | ||
} | ||
|
||
override fun getChildren(): Array<VirtualFile> { | ||
if (file.isFile || !file.exists()) return emptyArray() | ||
throw UnsupportedOperationException("getChildren " + file.absolutePath) | ||
} | ||
|
||
override fun getOutputStream(p0: Any?, p1: Long, p2: Long): OutputStream = | ||
throw UnsupportedOperationException() | ||
|
||
override fun contentsToByteArray(): ByteArray { | ||
if (content != null) return content.toByteArray() | ||
return FileUtil.loadFileBytes(file) | ||
} | ||
|
||
override fun getTimeStamp(): Long = | ||
throw UnsupportedOperationException() | ||
|
||
override fun getLength(): Long = file.length() | ||
|
||
override fun refresh(p0: Boolean, p1: Boolean, p2: Runnable?) = | ||
throw UnsupportedOperationException() | ||
|
||
override fun getInputStream(): InputStream = | ||
throw UnsupportedOperationException() | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.