From f44acf4f448c65f4cf54c2dcb4313eb59189a77b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:56:11 +0100 Subject: [PATCH] SONARKT-400 Integrate kotlin-analysis-api --- build.gradle.kts | 5 + gradle/verification-metadata.xml | 40 ++++++ sonar-kotlin-api/build.gradle.kts | 21 +++ .../org/sonarsource/kotlin/api/frontend/K1.kt | 126 +++++++++++++++++ .../org/sonarsource/kotlin/api/frontend/K2.kt | 133 ++++++++++++++++++ .../frontend/KotlinCoreEnvironmentTools.kt | 12 +- .../kotlin/api/frontend/KotlinFileContext.kt | 4 + .../kotlin/api/frontend/KotlinTree.kt | 10 +- ...ModuleProviderByCompilerConfiguration.java | 51 +++++++ .../AbstractKotlinSensorExecuteContext.kt | 4 +- .../kotlin/api/visiting/KotlinFileVisitor.kt | 37 ++++- .../KotlinCoreEnvironmentToolsTest.kt | 66 +++++++++ .../api/sensors/AbstractKotlinSensorTest.kt | 1 + .../kotlin/checks/AnchorPrecedenceCheck.kt | 1 + .../kotlin/checks/AndroidBroadcastingCheck.kt | 1 + .../checks/ArrayHashCodeAndToStringCheck.kt | 1 + .../AuthorisingNonAuthenticatedUsersCheck.kt | 1 + .../checks/BiometricAuthWithoutCryptoCheck.kt | 1 + .../kotlin/checks/CipherBlockChainingCheck.kt | 1 + .../kotlin/checks/CipherModeOperationCheck.kt | 1 + .../kotlin/checks/ClearTextProtocolCheck.kt | 1 + .../checks/CollectionCallingItselfCheck.kt | 1 + .../CollectionInappropriateCallsCheck.kt | 1 + .../CollectionShouldBeImmutableCheck.kt | 1 + .../CollectionSizeAndArrayLengthCheck.kt | 1 + .../CoroutineScopeFunSuspendingCheck.kt | 1 + .../checks/CoroutinesTimeoutApiUnusedCheck.kt | 1 + .../kotlin/checks/DataHashingCheck.kt | 1 + .../kotlin/checks/DebugFeatureEnabledCheck.kt | 1 + .../kotlin/checks/DelegationPatternCheck.kt | 1 + .../kotlin/checks/DeprecatedCodeCheck.kt | 1 + .../kotlin/checks/DeprecatedCodeUsedCheck.kt | 1 + .../kotlin/checks/DuplicateBranchCheck.kt | 1 + .../checks/DuplicatesInCharacterClassCheck.kt | 1 + .../kotlin/checks/EmptyLineRegexCheck.kt | 1 + .../checks/EmptyStringRepetitionCheck.kt | 1 + .../kotlin/checks/EncryptionAlgorithmCheck.kt | 1 + .../kotlin/checks/EqualsArgumentTypeCheck.kt | 1 + .../kotlin/checks/EqualsMethodUsageCheck.kt | 1 + .../EqualsOverriddenWithArrayFieldCheck.kt | 1 + .../EqualsOverridenWithHashCodeCheck.kt | 1 + .../kotlin/checks/ExposedMutableFlowCheck.kt | 1 + .../ExternalAndroidStorageAccessCheck.kt | 1 + .../kotlin/checks/FinalFlowOperationCheck.kt | 1 + ...wChannelReturningFunsNotSuspendingCheck.kt | 1 + .../checks/GraphemeClustersInClassesCheck.kt | 1 + .../checks/IgnoredOperationStatusCheck.kt | 1 + .../kotlin/checks/IndexedAccessCheck.kt | 1 + .../checks/InjectableDispatchersCheck.kt | 1 + .../checks/InterfaceCouldBeFunctionalCheck.kt | 1 + .../kotlin/checks/InvalidRegexCheck.kt | 1 + .../kotlin/checks/IsInstanceMethodCheck.kt | 1 + .../kotlin/checks/LiftReturnStatementCheck.kt | 1 + .../kotlin/checks/MainSafeCoroutinesCheck.kt | 1 + .../MapValuesShouldBeAccessedSafelyCheck.kt | 1 + .../MobileDatabaseEncryptionKeysCheck.kt | 1 + .../PreparedStatementAndResultSetCheck.kt | 1 + .../PropertyGetterAndSetterUsageCheck.kt | 1 + .../kotlin/checks/PseudoRandomCheck.kt | 1 + .../kotlin/checks/ReasonableTypeCastsCheck.kt | 1 + .../kotlin/checks/ReceivingIntentsCheck.kt | 1 + .../RedundantMethodsInDataClassesCheck.kt | 1 + .../checks/RedundantSuspendModifierCheck.kt | 1 + .../kotlin/checks/RedundantTypeCastsCheck.kt | 1 + .../kotlin/checks/RegexComplexityCheck.kt | 1 + .../kotlin/checks/ReluctantQuantifierCheck.kt | 1 + .../checks/ReplaceGuavaWithKotlinCheck.kt | 1 + .../checks/RobustCryptographicKeysCheck.kt | 1 + .../kotlin/checks/RunFinalizersCheck.kt | 1 + .../kotlin/checks/SamConversionCheck.kt | 1 + .../ScheduledThreadPoolExecutorZeroCheck.kt | 1 + .../kotlin/checks/ServerCertificateCheck.kt | 1 + .../checks/SimplifiedPreconditionsCheck.kt | 1 + ...fyFilteringBeforeTerminalOperationCheck.kt | 1 + .../checks/SimplifySizeExpressionCheck.kt | 1 + .../kotlin/checks/SingletonPatternCheck.kt | 1 + .../kotlin/checks/StreamNotConsumedCheck.kt | 1 + .../checks/StrongCipherAlgorithmCheck.kt | 1 + .../StructuredConcurrencyPrinciplesCheck.kt | 1 + .../SuspendingFunCallerDispatcherCheck.kt | 1 + .../UnencryptedDatabaseOnMobileCheck.kt | 1 + ...encryptedFilesInMobileApplicationsCheck.kt | 1 + .../checks/UnicodeAwareCharClassesCheck.kt | 1 + .../kotlin/checks/UnnecessaryImportsCheck.kt | 1 + .../checks/UnpredictableHashSaltCheck.kt | 1 + .../UnpredictableSecureRandomSaltCheck.kt | 1 + ...itedFindFunctionWithNullComparisonCheck.kt | 1 + .../checks/UnusedDeferredResultCheck.kt | 1 + .../kotlin/checks/UnusedLocalVariableCheck.kt | 1 + .../kotlin/checks/UnusedPrivateMethodCheck.kt | 1 + .../kotlin/checks/UselessAssignmentsCheck.kt | 1 + .../kotlin/checks/UselessIncrementCheck.kt | 1 + .../kotlin/checks/UselessNullCheckCheck.kt | 1 + .../kotlin/checks/VarShouldBeValCheck.kt | 1 + .../checks/VerifiedServerHostnamesCheck.kt | 1 + .../ViewModelSuspendingFunctionsCheck.kt | 1 + .../kotlin/checks/VoidShouldBeUnitCheck.kt | 1 + .../kotlin/checks/WeakSSLContextCheck.kt | 1 + .../checks/WebViewJavaScriptSupportCheck.kt | 1 + .../kotlin/checks/WebViewsFileAccessCheck.kt | 1 + .../sonarsource/kotlin/checks/CheckTest.kt | 18 ++- .../kotlin/gradle/KotlinGradleSensor.kt | 1 + sonar-kotlin-plugin/build.gradle.kts | 8 +- .../sonarsource/kotlin/plugin/KotlinSensor.kt | 2 + .../linking/WorkaroundForJarMinimization.java | 12 ++ .../kotlin/plugin/KotlinSensorTest.kt | 20 ++- .../WorkaroundForJarMinimizationTest.kt | 2 +- .../kotlin/testapi/KotlinVerifier.kt | 4 +- .../sonarsource/kotlin/testapi/TestUtils.kt | 21 ++- 109 files changed, 674 insertions(+), 11 deletions(-) create mode 100644 sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K1.kt create mode 100644 sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K2.kt create mode 100644 sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KtModuleProviderByCompilerConfiguration.java diff --git a/build.gradle.kts b/build.gradle.kts index ee609d79e..e12330f28 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -87,6 +87,11 @@ allprojects { repositories { mavenCentral() + maven(url = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies") { + content { + includeGroup("org.jetbrains.kotlin") + } + } } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 72e832da3..2ee32e075 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -805,6 +805,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1430,6 +1460,16 @@ + + + + + + + + + + diff --git a/sonar-kotlin-api/build.gradle.kts b/sonar-kotlin-api/build.gradle.kts index 810fb649a..8830878b5 100644 --- a/sonar-kotlin-api/build.gradle.kts +++ b/sonar-kotlin-api/build.gradle.kts @@ -3,6 +3,27 @@ plugins { } dependencies { + listOf( + // Source of these artifacts is + // https://github.com/JetBrains/kotlin/tree/v2.0.21/prepare/ide-plugin-dependencies + // where ones whose name contains "high-level" are deprecated and should not be used - see + // https://github.com/JetBrains/kotlin/commit/3ad9798a17ad9eb68cdb1e9f8f1a69584151bfd4 + "org.jetbrains.kotlin:analysis-api-standalone-for-ide", + "org.jetbrains.kotlin:analysis-api-platform-interface-for-ide", + "org.jetbrains.kotlin:analysis-api-for-ide", // old name "high-level-api-for-ide" + "org.jetbrains.kotlin:analysis-api-impl-base-for-ide", // old name "high-level-api-impl-base" + "org.jetbrains.kotlin:analysis-api-fe10-for-ide", // old name "high-level-api-fe10" + "org.jetbrains.kotlin:analysis-api-k2-for-ide", // old name "high-level-api-k2" + "org.jetbrains.kotlin:low-level-api-fir-for-ide", + "org.jetbrains.kotlin:symbol-light-classes-for-ide" + ).forEach { + val kotlinVersion: String by project.ext + api("$it:$kotlinVersion") { + // https://youtrack.jetbrains.com/issue/KT-61639/Standalone-Analysis-API-cannot-find-transitive-dependencies + isTransitive = false + } + } + compileOnly(libs.sonar.plugin.api) compileOnly(libs.slf4j.api) implementation(libs.sonar.analyzer.commons) diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K1.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K1.kt new file mode 100644 index 000000000..e20daa070 --- /dev/null +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K1.kt @@ -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()) + } +} diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K2.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K2.kt new file mode 100644 index 000000000..a46aa10f8 --- /dev/null +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/K2.kt @@ -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, +): 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 { + 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() + +} diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentTools.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentTools.kt index c5638c51a..e6668570d 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentTools.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentTools.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import com.intellij.openapi.Disposable -import com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration @@ -52,10 +52,20 @@ class Environment( val classpath: List, kotlinLanguageVersion: LanguageVersion, javaLanguageVersion: JvmTarget = JvmTarget.JVM_1_8, + val useK2: Boolean = false, ) { val configuration = compilerConfiguration(classpath, kotlinLanguageVersion, javaLanguageVersion) + // K1 val env = kotlinCoreEnvironment(configuration, disposable) val ktPsiFactory: KtPsiFactory = KtPsiFactory(env.project, false) + // K2 + var k2session: StandaloneAnalysisAPISession? = null + + init { + if (!useK2) { + configureK1AnalysisApiServices(env) + } + } } fun kotlinCoreEnvironment( diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinFileContext.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinFileContext.kt index 943920efd..b577cfd97 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinFileContext.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinFileContext.kt @@ -27,6 +27,10 @@ import org.sonarsource.kotlin.api.reporting.SecondaryLocation data class KotlinFileContext( val inputFileContext: InputFileContext, val ktFile: KtFile, + /** + * @see [org.sonarsource.kotlin.api.visiting.withKaSession] + */ + @Deprecated("use kotlin-analysis-api instead") val bindingContext: BindingContext, val diagnostics: List, val regexCache: RegexCache, diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinTree.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinTree.kt index 44c1a01cf..375c69fb2 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinTree.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KotlinTree.kt @@ -17,6 +17,7 @@ package org.sonarsource.kotlin.api.frontend import com.intellij.openapi.editor.Document +import com.intellij.openapi.util.io.FileUtil import com.intellij.psi.PsiElement import com.intellij.psi.PsiErrorElement import com.intellij.psi.PsiFile @@ -33,6 +34,7 @@ class KotlinTree( val bindingContext: BindingContext, val diagnostics: List, val regexCache: RegexCache, + val doResolve: Boolean, ) data class KotlinSyntaxStructure(val ktFile: KtFile, val document: Document, val inputFile: InputFile) { @@ -40,7 +42,13 @@ data class KotlinSyntaxStructure(val ktFile: KtFile, val document: Document, val @JvmStatic fun of(content: String, environment: Environment, inputFile: InputFile): KotlinSyntaxStructure { - val psiFile: KtFile = environment.ktPsiFactory.createFile(inputFile.uri().path, normalizeEol(content)) + val psiFile: KtFile = if (environment.k2session != null) { + val inputFilePath = FileUtil.toSystemIndependentName(inputFile.file().path) + environment.k2session!!.modulesWithFiles.values.first().find { + it.virtualFile.path == inputFilePath + } as KtFile + } else + environment.ktPsiFactory.createFile(inputFile.uri().path, normalizeEol(content)) val document = try { psiFile.viewProvider.document ?: throw ParseException("Cannot extract document") diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KtModuleProviderByCompilerConfiguration.java b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KtModuleProviderByCompilerConfiguration.java new file mode 100644 index 000000000..2d8520b4b --- /dev/null +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/frontend/KtModuleProviderByCompilerConfiguration.java @@ -0,0 +1,51 @@ +/* + * 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 kotlin.jvm.functions.Function1; +import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISessionBuilder; +import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.KotlinStaticProjectStructureProvider; +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment; +import org.jetbrains.kotlin.config.CompilerConfiguration; +import org.jetbrains.kotlin.psi.KtFile; + +import java.util.List; + +/** + * @deprecated use {@link StandaloneAnalysisAPISessionBuilder#buildKtModuleProvider(Function1)} instead + */ +@Deprecated(forRemoval = true) +final class KtModuleProviderByCompilerConfiguration { + + @SuppressWarnings("KotlinInternalInJava") + static KotlinStaticProjectStructureProvider build( + KotlinCoreProjectEnvironment kotlinCoreProjectEnvironment, + CompilerConfiguration compilerConfig, + List ktFiles + ) { + return org.jetbrains.kotlin.analysis.project.structure.impl + .KaModuleUtilsKt.buildKtModuleProviderByCompilerConfiguration( + kotlinCoreProjectEnvironment, + compilerConfig, + ktFiles + ); + } + + private KtModuleProviderByCompilerConfiguration() { + } + +} diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorExecuteContext.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorExecuteContext.kt index 6ba830dd4..710e8684c 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorExecuteContext.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorExecuteContext.kt @@ -84,6 +84,8 @@ abstract class AbstractKotlinSensorExecuteContext( abstract val bindingContext: BindingContext + abstract val doResolve: Boolean + fun analyzeFiles(): Boolean { try { val regexCache = RegexCache() @@ -93,7 +95,7 @@ abstract class AbstractKotlinSensorExecuteContext( }.forEach { (ktFile, doc, inputFile) -> if (sensorContext.isCancelled) return false val inputFileContext = InputFileContextImpl(sensorContext, inputFile, isInAndroidContext) - val tree = KotlinTree(ktFile, doc, bindingContext, getFileDiagnostics(ktFile), regexCache) + val tree = KotlinTree(ktFile, doc, bindingContext, getFileDiagnostics(ktFile), regexCache, doResolve) measureDuration(inputFile.filename()) { analyzeFile(inputFileContext, tree) diff --git a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt index fd828dad5..eda832e55 100644 --- a/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt +++ b/sonar-kotlin-api/src/main/java/org/sonarsource/kotlin/api/visiting/KotlinFileVisitor.kt @@ -16,13 +16,48 @@ */ package org.sonarsource.kotlin.api.visiting +import org.jetbrains.kotlin.analysis.api.KaSession +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.psi.KtFile import org.sonarsource.kotlin.api.checks.InputFileContext import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.frontend.KotlinTree +/** + * Executes the given [action] in a [KaSession] context + * providing access to [Kotlin Analysis API](https://kotl.in/analysis-api). + */ +inline fun withKaSession(action: KaSession.() -> R): R = action(kaSession!!) + +@PublishedApi +internal var kaSession: KaSession? = null + +/** + * Manages lifetime of [kaSession]. + */ +internal inline fun kaSession(ktFile: KtFile, action: () -> Unit) { + check(kaSession == null) + try { + analyze(ktFile) { + kaSession = this + action() + } + } finally { + kaSession = null + } +} + abstract class KotlinFileVisitor { fun scan(fileContext: InputFileContext, root: KotlinTree) { - visit(KotlinFileContext(fileContext, root.psiFile, root.bindingContext, root.diagnostics, root.regexCache)) + val kotlinFileContext = + KotlinFileContext(fileContext, root.psiFile, root.bindingContext, root.diagnostics, root.regexCache) + if (root.doResolve) { + kaSession(root.psiFile) { + visit(kotlinFileContext) + } + } else { + visit(kotlinFileContext) + } } abstract fun visit(kotlinFileContext: KotlinFileContext) diff --git a/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentToolsTest.kt b/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentToolsTest.kt index e790c1d12..5c4b896f7 100644 --- a/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentToolsTest.kt +++ b/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/frontend/KotlinCoreEnvironmentToolsTest.kt @@ -20,9 +20,16 @@ import org.assertj.core.api.Assertions.assertThat import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.psi.KtIsExpression +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.jetbrains.kotlin.resolve.BindingContext import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test +import org.sonarsource.kotlin.api.visiting.kaSession +import org.sonarsource.kotlin.api.visiting.withKaSession +import java.io.File class KotlinCoreEnvironmentToolsTest { @@ -44,4 +51,63 @@ class KotlinCoreEnvironmentToolsTest { .isNotEqualTo(BindingContext.EMPTY) } + // https://kotlinlang.org/docs/whatsnew20.html#smart-cast-improvements + private val content = """ + fun example(any: Any) { + val isString = any is String + if (isString) { + any.length + } + } + """.trimIndent() + + /** + * @see k2 + */ + @Test + fun k1() { + val environment = Environment( + disposable, + listOf(), + LanguageVersion.LATEST_STABLE, + JvmTarget.JVM_1_8, + useK2 = false, + ) + val ktFile = environment.ktPsiFactory.createFile("/fake.kt", content) + analyzeAndGetBindingContext(environment.env, listOf(ktFile)) + kaSession(ktFile) { + withKaSession { + assertThat(ktFile.findDescendantOfType()!!.expressionType.toString()) + .isEqualTo("kotlin/Boolean") + assertThat(ktFile.findDescendantOfType()!!.expressionType.toString()) + .isEqualTo("kotlin/Unit") + } + } + } + + /** + * @see k1 + */ + @Test + fun k2() { + val analysisSession = createK2AnalysisSession( + disposable, + compilerConfiguration( + listOf(), + LanguageVersion.LATEST_STABLE, + JvmTarget.JVM_1_8, + ), + listOf(KotlinVirtualFile(KotlinFileSystem(), File("/fake.kt"), content)), + ) + val ktFile: KtFile = analysisSession.modulesWithFiles.entries.first().value[0] as KtFile + kaSession(ktFile) { + withKaSession { + assertThat(ktFile.findDescendantOfType()!!.expressionType.toString()) + .isEqualTo("kotlin/Boolean") + assertThat(ktFile.findDescendantOfType()!!.expressionType.toString()) + .isEqualTo("kotlin/Int") + } + } + } + } diff --git a/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorTest.kt b/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorTest.kt index 58144380b..2d89bdddd 100644 --- a/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorTest.kt +++ b/sonar-kotlin-api/src/test/java/org/sonarsource/kotlin/api/sensors/AbstractKotlinSensorTest.kt @@ -195,6 +195,7 @@ class DummyKotlinSensor(checkFactory: CheckFactory, language: KotlinLanguage, ch sensorContext, filesToAnalyze, progressReport, listOf(KtChecksVisitor(checks)), filenames, LOG ) { override val bindingContext: BindingContext = BindingContext.EMPTY + override val doResolve: Boolean = false } override fun getFilesToAnalyse(sensorContext: SensorContext): Iterable = diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AnchorPrecedenceCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AnchorPrecedenceCheck.kt index 7ddb22666..4ed3a2677 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AnchorPrecedenceCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AnchorPrecedenceCheck.kt @@ -22,6 +22,7 @@ import org.sonarsource.analyzer.commons.regex.finders.AnchorPrecedenceFinder import org.sonarsource.kotlin.api.regex.AbstractRegexCheck import org.sonarsource.kotlin.api.regex.RegexContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5850") class AnchorPrecedenceCheck : AbstractRegexCheck() { override fun visitRegex(regex: RegexParseResult, regexContext: RegexContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AndroidBroadcastingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AndroidBroadcastingCheck.kt index 2db930561..57d727ae1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AndroidBroadcastingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AndroidBroadcastingCheck.kt @@ -35,6 +35,7 @@ private val STICKY_BROADCAST_NAMES = setOf( "sendStickyOrderedBroadcastAsUser", ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5320") class AndroidBroadcastingCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt index b6b08db7d..1847ff695 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ArrayHashCodeAndToStringCheck.kt @@ -52,6 +52,7 @@ private val PRIMITIVE_ARRAY_REPLACEMENT = mapOf("hashCode" to "contentHashCode", private val OBJECT_ARRAY_REPLACEMENT = mapOf("hashCode" to "contentDeepHashCode", "toString" to "contentDeepToString") private val ARRAY_OF_ARRAY_REPLACEMENT = mapOf("contentHashCode" to "contentDeepHashCode", "contentToString" to "contentDeepToString") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2116") class ArrayHashCodeAndToStringCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt index ae54ac6ab..2b45df348 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/AuthorisingNonAuthenticatedUsersCheck.kt @@ -39,6 +39,7 @@ private val KEY_GEN_BUILDER_SET_AUTH_MATCHER = FunMatcher(qualifier = BUILDER, n withArguments("kotlin.Boolean") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6288") class AuthorisingNonAuthenticatedUsersCheck : CallAbstractCheck() { override val functionsToVisit = listOf(KEY_GEN_BUILDER_BUILD_MATCHER) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/BiometricAuthWithoutCryptoCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/BiometricAuthWithoutCryptoCheck.kt index 2019c4457..d2290a471 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/BiometricAuthWithoutCryptoCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/BiometricAuthWithoutCryptoCheck.kt @@ -33,6 +33,7 @@ private val ANDROIDX_AUTH = FunMatcher(qualifier = "androidx.biometric.Biometric private const val MESSAGE = """Make sure performing a biometric authentication without a "CryptoObject" is safe here.""" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6293") class BiometricAuthWithoutCryptoCheck : CallAbstractCheck() { override val functionsToVisit = setOf(ANDROID_HARDWARE_AUTH, ANDROIDX_AUTH) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt index 1d140b013..b122502e3 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherBlockChainingCheck.kt @@ -46,6 +46,7 @@ private val GET_INSTANCE_MATCHER = FunMatcher(qualifier = "javax.crypto.Cipher", private val GET_BYTES_MATCHER = FunMatcher(qualifier = "kotlin.text", name = "toByteArray") private val IV_PARAMETER_SPEC_MATCHER = ConstructorMatcher("javax.crypto.spec.IvParameterSpec") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S3329") class CipherBlockChainingCheck : CallAbstractCheck() { override val functionsToVisit = listOf(CIPHER_INIT_MATCHER) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt index 70a6a89fc..cfa9bd1a7 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CipherModeOperationCheck.kt @@ -44,6 +44,7 @@ private val GCM_PARAMETER_SPEC_MATCHER = ConstructorMatcher("javax.crypto.spec.G private val GET_BYTES_MATCHER = FunMatcher(qualifier = "kotlin.text", name = "toByteArray") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6432") class CipherModeOperationCheck : CallAbstractCheck() { override val functionsToVisit = listOf(CIPHER_INIT_MATCHER) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt index fb907c6ba..c4bd57fbd 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ClearTextProtocolCheck.kt @@ -60,6 +60,7 @@ private val ANDROID_SET_MIXED_CONTENT_MODE = FunMatcher(definingSupertype = "and private fun msg(insecure: String, replaceWith: String) = "Using $insecure is insecure. Use $replaceWith instead." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5332") class ClearTextProtocolCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionCallingItselfCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionCallingItselfCheck.kt index f4c37e9dc..bc1e4ee05 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionCallingItselfCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionCallingItselfCheck.kt @@ -35,6 +35,7 @@ private val COLLECTIONS_FUN_MATCHER = FunMatcher(definingSupertype = "kotlin.col private const val MESSAGE = "Collections should not be passed as arguments to their own methods." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2114") class CollectionCallingItselfCheck : CallAbstractCheck() { override val functionsToVisit = listOf(MUTABLE_COLLECTION_FUN_MATCHER, COLLECTIONS_FUN_MATCHER) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt index 222e429f6..31918daf5 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionInappropriateCallsCheck.kt @@ -66,6 +66,7 @@ val funMatcherToArgumentIndexMap = mapOf( const val ISSUE_MESSAGE = "This key/object cannot ever be present in the collection" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2175") class CollectionInappropriateCallsCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt index b574e1d0f..c2c83c7d4 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionShouldBeImmutableCheck.kt @@ -67,6 +67,7 @@ private val mutableCollections = "kotlin.collections.MutableCollection" ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6524") class CollectionShouldBeImmutableCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt index 1317b1ef9..d8a5c27f8 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CollectionSizeAndArrayLengthCheck.kt @@ -43,6 +43,7 @@ val ISSUE_MESSAGE_SIZE_NEVER_LT = """The size of an array/collection is never "< val ISSUE_MESSAGE_SIZE_ALWAYS_GTEQ = """The size of an array/collection is always ">=0", update this test to either ".isNotEmpty()" or ".isEmpty()".""" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S3981") class CollectionSizeAndArrayLengthCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt index 176277c22..17de3876e 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutineScopeFunSuspendingCheck.kt @@ -30,6 +30,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val COROUTINE_SCOPE = "kotlinx.coroutines.CoroutineScope" private const val MESSAGE = "Extension functions on CoroutineScope should not be suspending." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6312") class CoroutineScopeFunSuspendingCheck : AbstractCheck() { override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt index 7a5739bd0..43b03a509 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/CoroutinesTimeoutApiUnusedCheck.kt @@ -44,6 +44,7 @@ private val LAUNCH_ASYNC_MATCHER = FunMatcher(qualifier = KOTLINX_COROUTINES_PAC withNames("launch", "async") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6316") class CoroutinesTimeoutApiUnusedCheck : CallAbstractCheck() { override val functionsToVisit = listOf(FunMatcher(definingSupertype = "$KOTLINX_COROUTINES_PACKAGE.Job", name = "cancel")) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DataHashingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DataHashingCheck.kt index 6227e4e54..374f6c0bb 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DataHashingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DataHashingCheck.kt @@ -95,6 +95,7 @@ private val WEAK_METHOD_MATCHERS = listOf( private val DEPRECATED_SPRING_PASSWORD_ENCODER_METHODS = DEPRECATED_SPRING_PASSWORD_ENCODERS.map(::ConstructorMatcher).toList() + FunMatcher(qualifier = "org.springframework.security.crypto.password.NoOpPasswordEncoder", name = GET_INSTANCE) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4790") class DataHashingCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DebugFeatureEnabledCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DebugFeatureEnabledCheck.kt index e1c13801b..3d3450bb7 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DebugFeatureEnabledCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DebugFeatureEnabledCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val MESSAGE = "Make sure this debug feature is deactivated before delivering the code in production." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4507") class DebugFeatureEnabledCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt index 0f746cb0d..0cfbd44a5 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DelegationPatternCheck.kt @@ -46,6 +46,7 @@ import org.sonarsource.kotlin.api.checks.returnType import org.sonarsource.kotlin.api.checks.returnTypeAsString import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6514") class DelegationPatternCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt index 704082b13..35ac9e41a 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeCheck.kt @@ -28,6 +28,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.annotatedElement import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1133") class DeprecatedCodeCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeUsedCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeUsedCheck.kt index 509cd341c..70676750b 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeUsedCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DeprecatedCodeUsedCheck.kt @@ -27,6 +27,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1874") class DeprecatedCodeUsedCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt index 624f0bad9..11de86612 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicateBranchCheck.kt @@ -26,6 +26,7 @@ import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1871") class DuplicateBranchCheck : AbstractBranchDuplication() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicatesInCharacterClassCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicatesInCharacterClassCheck.kt index 30831dd4f..920c90393 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicatesInCharacterClassCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/DuplicatesInCharacterClassCheck.kt @@ -22,6 +22,7 @@ import org.sonarsource.analyzer.commons.regex.finders.DuplicatesInCharacterClass import org.sonarsource.kotlin.api.regex.AbstractRegexCheck import org.sonarsource.kotlin.api.regex.RegexContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5869") class DuplicatesInCharacterClassCheck : AbstractRegexCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt index 5bfc2520e..9a03bc599 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyLineRegexCheck.kt @@ -66,6 +66,7 @@ private val PATTERN_FIND = FunMatcher(qualifier = "java.util.regex.Matcher", nam private val STRING_IS_EMPTY = FunMatcher(qualifier = KOTLIN_TEXT, name = "isEmpty") private val REGEX_FIND = FunMatcher(qualifier = "kotlin.text.Regex", name = "find") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5846") class EmptyLineRegexCheck : AbstractRegexCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyStringRepetitionCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyStringRepetitionCheck.kt index 779d4b4ee..286706a92 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyStringRepetitionCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EmptyStringRepetitionCheck.kt @@ -22,6 +22,7 @@ import org.sonarsource.analyzer.commons.regex.finders.EmptyStringRepetitionFinde import org.sonarsource.kotlin.api.regex.AbstractRegexCheck import org.sonarsource.kotlin.api.regex.RegexContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5842") class EmptyStringRepetitionCheck : AbstractRegexCheck() { override fun visitRegex(regex: RegexParseResult, regexContext: RegexContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt index acbcb469a..ca34095f4 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EncryptionAlgorithmCheck.kt @@ -33,6 +33,7 @@ val CIPHER_GET_INSTANCE_MATCHER = FunMatcher { name = "getInstance" } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5542") class EncryptionAlgorithmCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt index 6b6dbf706..0d6b26849 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsArgumentTypeCheck.kt @@ -47,6 +47,7 @@ private val EQUALS_MATCHER = FunMatcher { withArguments(ANY_TYPE) } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2097") class EqualsArgumentTypeCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsMethodUsageCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsMethodUsageCheck.kt index 255a761a5..e54b35b8e 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsMethodUsageCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsMethodUsageCheck.kt @@ -33,6 +33,7 @@ import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6519") class EqualsMethodUsageCheck : CallAbstractCheck() { override val functionsToVisit = setOf(FunMatcher { name = EQUALS_METHOD_NAME; withArguments(ANY_TYPE) }) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverriddenWithArrayFieldCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverriddenWithArrayFieldCheck.kt index b39958209..315671362 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverriddenWithArrayFieldCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverriddenWithArrayFieldCheck.kt @@ -41,6 +41,7 @@ private val EXPECTED_OVERRIDES = listOf( } ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6218") class EqualsOverriddenWithArrayFieldCheck : AbstractCheck() { override fun visitClass(klass: KtClass, context: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverridenWithHashCodeCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverridenWithHashCodeCheck.kt index 8f587aab6..724bbb75f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverridenWithHashCodeCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/EqualsOverridenWithHashCodeCheck.kt @@ -39,6 +39,7 @@ private val hashCodeMatcher = FunMatcher { withNoArguments() } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1206") class EqualsOverridenWithHashCodeCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExposedMutableFlowCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExposedMutableFlowCheck.kt index af25d1bbd..0f3deaba7 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExposedMutableFlowCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExposedMutableFlowCheck.kt @@ -35,6 +35,7 @@ private val DISALLOWED_TYPES = listOf( private const val MESSAGE = "Don't expose mutable flow types." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6305") class ExposedMutableFlowCheck : AbstractCheck() { override fun visitProperty(property: KtProperty, kotlinFileContext: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt index 16d1a70e9..07e65ded8 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ExternalAndroidStorageAccessCheck.kt @@ -58,6 +58,7 @@ private val HOTSPOT_PROPS = listOf( "obbDirs", ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5324") class ExternalAndroidStorageAccessCheck : CallAbstractCheck() { override val functionsToVisit = HOTSPOT_FUNS diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt index 376cf130d..92d9456df 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FinalFlowOperationCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val MESSAGE = "Unused coroutines Flow." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6314") class FinalFlowOperationCheck : CallAbstractCheck() { override val functionsToVisit = listOf(FunMatcher(returnType = COROUTINES_FLOW)) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FlowChannelReturningFunsNotSuspendingCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FlowChannelReturningFunsNotSuspendingCheck.kt index 4d2df5bc0..6ecfaa1be 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FlowChannelReturningFunsNotSuspendingCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/FlowChannelReturningFunsNotSuspendingCheck.kt @@ -30,6 +30,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private val FORBIDDEN_RETURN_TYPES = listOf(COROUTINES_FLOW, COROUTINES_CHANNEL) private const val MESSAGE = """Functions returning "Flow" or "Channel" should not be suspending""" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6309") class FlowChannelReturningFunsNotSuspendingCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/GraphemeClustersInClassesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/GraphemeClustersInClassesCheck.kt index eb2ad1c07..23bd456a7 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/GraphemeClustersInClassesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/GraphemeClustersInClassesCheck.kt @@ -22,6 +22,7 @@ import org.sonarsource.analyzer.commons.regex.finders.GraphemeInClassFinder import org.sonarsource.kotlin.api.regex.AbstractRegexCheck import org.sonarsource.kotlin.api.regex.RegexContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5868") class GraphemeClustersInClassesCheck : AbstractRegexCheck() { override fun visitRegex(regex: RegexParseResult, regexContext: RegexContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt index 3c543f99a..c520056f9 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IgnoredOperationStatusCheck.kt @@ -25,6 +25,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.simpleName import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S899") class IgnoredOperationStatusCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IndexedAccessCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IndexedAccessCheck.kt index 4a2eb4d75..ad1a66792 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IndexedAccessCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IndexedAccessCheck.kt @@ -26,6 +26,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.FunMatcherImpl import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6518") class IndexedAccessCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt index 0e20fb0e5..9a4fd7772 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InjectableDispatchersCheck.kt @@ -33,6 +33,7 @@ import org.sonarsource.kotlin.api.frontend.secondaryOf private const val MESSAGE = "Avoid hardcoded dispatchers." private const val DISPATCHERS_OBJECT = "$KOTLINX_COROUTINES_PACKAGE.Dispatchers" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6310") class InjectableDispatchersCheck : CallAbstractCheck() { override val functionsToVisit = FUNS_ACCEPTING_DISPATCHERS diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt index f24a39b22..0ca3392db 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InterfaceCouldBeFunctionalCheck.kt @@ -26,6 +26,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.getType import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6517") class InterfaceCouldBeFunctionalCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InvalidRegexCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InvalidRegexCheck.kt index a0fce121e..0a2599a21 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InvalidRegexCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/InvalidRegexCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val MESSAGE_MULTIPLE_ERRORS = "Fix the syntax errors inside this regex." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5856") class InvalidRegexCheck : AbstractRegexCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt index 8dad42147..c477245e9 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/IsInstanceMethodCheck.kt @@ -35,6 +35,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private val JAVA_CLASS_KEYWORDS = listOf("java", "javaClass") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6202") class IsInstanceMethodCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/LiftReturnStatementCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/LiftReturnStatementCheck.kt index a1aee3688..a0e518e7f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/LiftReturnStatementCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/LiftReturnStatementCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.isExhaustive import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6510") class LiftReturnStatementCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt index 88355946c..c8913883c 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MainSafeCoroutinesCheck.kt @@ -67,6 +67,7 @@ val BLOCKING_ANNOTATIONS = setOf( "javax.net.ssl.SSLException", ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6307") class MainSafeCoroutinesCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt index 9c1ed66c6..983ebd7f4 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MapValuesShouldBeAccessedSafelyCheck.kt @@ -33,6 +33,7 @@ import org.sonarsource.kotlin.api.reporting.message import org.sonarsource.kotlin.api.checks.determineType import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6611") class MapValuesShouldBeAccessedSafelyCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt index 917b77c97..ff80b0d5b 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/MobileDatabaseEncryptionKeysCheck.kt @@ -45,6 +45,7 @@ private const val ENCRYPTION_KEY = "encryptionKey" private const val CHANGE_PASSWORD = "changePassword" private val CREATE_CHAR_BYTE_ARRAY = FunMatcher(qualifier = "kotlin") { withNames("byteArrayOf", "charArrayOf") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6301") class MobileDatabaseEncryptionKeysCheck : CallAbstractCheck() { override val functionsToVisit = listOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt index dfadb6416..e3cc890ad 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PreparedStatementAndResultSetCheck.kt @@ -44,6 +44,7 @@ private val RESULT_SET_GET = FunMatcher(qualifier = "java.sql.ResultSet", nameRe withArguments(ArgumentMatcher(INT_TYPE), ArgumentMatcher.ANY) } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2695") class PreparedStatementAndResultSetCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt index b7d0f0ed3..da105a7f1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PropertyGetterAndSetterUsageCheck.kt @@ -41,6 +41,7 @@ import org.sonarsource.kotlin.api.frontend.secondaryOf private val GETTER_PREFIX = Regex("""^(get|is)\p{javaUpperCase}""") private val SETTER_PREFIX = Regex("""^set\p{javaUpperCase}""") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6512") class PropertyGetterAndSetterUsageCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt index 261a4687a..fb82c0c05 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/PseudoRandomCheck.kt @@ -47,6 +47,7 @@ private val RANDOM_CONSTRUCTOR_TYPES = setOf( "org.apache.commons.lang.math.JVMRandom" ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2245") class PseudoRandomCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReasonableTypeCastsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReasonableTypeCastsCheck.kt index d25c9551c..21aa21cc9 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReasonableTypeCastsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReasonableTypeCastsCheck.kt @@ -22,6 +22,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6530") class ReasonableTypeCastsCheck : AbstractCheck() { override fun visitKtFile(file: KtFile, context: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReceivingIntentsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReceivingIntentsCheck.kt index 6feb431e3..0e3242b18 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReceivingIntentsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReceivingIntentsCheck.kt @@ -24,6 +24,7 @@ import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.isNull import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5322") class ReceivingIntentsCheck : CallAbstractCheck() { override val functionsToVisit = listOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantMethodsInDataClassesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantMethodsInDataClassesCheck.kt index 194065d24..1a9934251 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantMethodsInDataClassesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantMethodsInDataClassesCheck.kt @@ -52,6 +52,7 @@ private val HASHCODE_MATCHER = FunMatcher { private val OBJECTS_HASH_MATCHER = FunMatcher(qualifier = "java.util.Objects", name = "hash") private val ARRAYS_HASHCODE_MATCHER = FunMatcher(qualifier = "java.util.Arrays", name = "hashCode") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6207") class RedundantMethodsInDataClassesCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt index d7b4be0cd..809be533e 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantSuspendModifierCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.checks.overrides import org.sonarsource.kotlin.api.checks.suspendModifier import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6318") class RedundantSuspendModifierCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantTypeCastsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantTypeCastsCheck.kt index 56a51fe8a..15f020bf6 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantTypeCastsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RedundantTypeCastsCheck.kt @@ -24,6 +24,7 @@ import org.sonarsource.kotlin.api.reporting.Message import org.sonarsource.kotlin.api.reporting.message import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6531") class RedundantTypeCastsCheck : AbstractCheck() { override fun visitKtFile(file: KtFile, context: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RegexComplexityCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RegexComplexityCheck.kt index 4eb7695be..0acca9873 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RegexComplexityCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RegexComplexityCheck.kt @@ -25,6 +25,7 @@ import org.sonarsource.kotlin.api.regex.RegexContext private const val DEFAULT_MAX = 20 +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5843") class RegexComplexityCheck : AbstractRegexCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReluctantQuantifierCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReluctantQuantifierCheck.kt index d0144c380..2108255b0 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReluctantQuantifierCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReluctantQuantifierCheck.kt @@ -22,6 +22,7 @@ import org.sonarsource.analyzer.commons.regex.finders.ReluctantQuantifierFinder import org.sonarsource.kotlin.api.regex.AbstractRegexCheck import org.sonarsource.kotlin.api.regex.RegexContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5857") class ReluctantQuantifierCheck : AbstractRegexCheck() { override fun visitRegex(regex: RegexParseResult, regexContext: RegexContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt index f2125bbd6..136add58f 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ReplaceGuavaWithKotlinCheck.kt @@ -72,6 +72,7 @@ private val REPLACEMENT_TYPES = mapOf( GUAVA_OPTIONAL to """Use "java.util.Optional" instead.""", ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4738") class ReplaceGuavaWithKotlinCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt index 4e91e8ef5..b54b44a1a 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RobustCryptographicKeysCheck.kt @@ -72,6 +72,7 @@ private val INSECURE_EC_SPECS = setOf( ) private const val EC_MIN_KEY_SIZE = 224 +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4426") class RobustCryptographicKeysCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RunFinalizersCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RunFinalizersCheck.kt index 3269b9409..c00c87b94 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RunFinalizersCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/RunFinalizersCheck.kt @@ -23,6 +23,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2151") class RunFinalizersCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt index 5e691a6ba..0e8677ecd 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SamConversionCheck.kt @@ -25,6 +25,7 @@ import org.sonarsource.kotlin.api.checks.isFunctionalInterface import org.sonarsource.kotlin.api.checks.merge import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6516") class SamConversionCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ScheduledThreadPoolExecutorZeroCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ScheduledThreadPoolExecutorZeroCheck.kt index 4c7584bc8..5fe5e0072 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ScheduledThreadPoolExecutorZeroCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ScheduledThreadPoolExecutorZeroCheck.kt @@ -39,6 +39,7 @@ private val THREAD_POOL_CONSTRUCTOR_MATCHER = private val POOL_SIZE_SETTER_MATCHER = FunMatcher(definingSupertype = "java.util.concurrent.ThreadPoolExecutor", name = "setCorePoolSize") { withArguments("kotlin.Int") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2122") class ScheduledThreadPoolExecutorZeroCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt index 3bc73e349..36d6c0b72 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt @@ -44,6 +44,7 @@ private val funMatchers = listOf( }) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4830") class ServerCertificateCheck : AbstractCheck() { override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifiedPreconditionsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifiedPreconditionsCheck.kt index 760b838c3..8a9185dc8 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifiedPreconditionsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifiedPreconditionsCheck.kt @@ -52,6 +52,7 @@ private val ILLEGAL_ARGUMENT_EXCEPTION_CONSTRUCTOR_MATCH = ConstructorMatcher(ty withArguments("kotlin.String") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6532") class SimplifiedPreconditionsCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt index e0f8793b6..2d7433932 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifyFilteringBeforeTerminalOperationCheck.kt @@ -29,6 +29,7 @@ import org.sonarsource.kotlin.api.reporting.message private const val KOTLIN_COLLECTIONS_QUALIFIER = "kotlin.collections" private val FILTER_MATCHER = FunMatcher(qualifier = KOTLIN_COLLECTIONS_QUALIFIER, name = "filter") { withArguments("kotlin.Function1") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6527") class SimplifyFilteringBeforeTerminalOperationCheck : CallAbstractCheck() { override val functionsToVisit = listOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt index 334a912fd..9e9605854 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SimplifySizeExpressionCheck.kt @@ -79,6 +79,7 @@ private val lengthFieldMatcher = FieldMatcher { withQualifiers("kotlin.String") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6529") class SimplifySizeExpressionCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt index 9f5c136c3..32e779131 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SingletonPatternCheck.kt @@ -46,6 +46,7 @@ private val lazyInitializationMatcher = FunMatcher( definingSupertype = "kotlin" ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6515") class SingletonPatternCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt index ab16380ab..0bcb3c43a 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StreamNotConsumedCheck.kt @@ -44,6 +44,7 @@ private val SEQUENCE_MATCHER = FunMatcher(qualifier = "kotlin.sequences") { ) } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S3958") class StreamNotConsumedCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StrongCipherAlgorithmCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StrongCipherAlgorithmCheck.kt index b8240b7da..6807559a4 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StrongCipherAlgorithmCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StrongCipherAlgorithmCheck.kt @@ -39,6 +39,7 @@ private const val msg = "Use a strong cipher algorithm." private val cipherGetInstanceMatcher = FunMatcher(qualifier = "javax.crypto.Cipher", name = "getInstance") private val nullCipherConstructorMatcher = ConstructorMatcher("javax.crypto.NullCipher") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5547") class StrongCipherAlgorithmCheck : AbstractCheck() { override fun visitCallExpression(callExpr: KtCallExpression, kotlinFileContext: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt index c9aa001dc..6d97de775 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/StructuredConcurrencyPrinciplesCheck.kt @@ -42,6 +42,7 @@ private val SUPERVISOR_JOB_CONSTRUCTOR = FunMatcher(qualifier = KOTLINX_COROUTIN private const val MESSAGE_ENDING = " here leads to the breaking of structured concurrency principles." private const val DELICATE_API_CLASS_TYPE = "kotlin.reflect.KClass" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6306") class StructuredConcurrencyPrinciplesCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt index ac8d415c7..a43608ff8 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/SuspendingFunCallerDispatcherCheck.kt @@ -27,6 +27,7 @@ import org.sonarsource.kotlin.api.checks.CallAbstractCheck import org.sonarsource.kotlin.api.checks.FUNS_ACCEPTING_DISPATCHERS import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6311") class SuspendingFunCallerDispatcherCheck : CallAbstractCheck() { override val functionsToVisit = FUNS_ACCEPTING_DISPATCHERS diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt index 55b090698..46ad849ec 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedDatabaseOnMobileCheck.kt @@ -38,6 +38,7 @@ private val REALM_ENC_KEY_FUN = FunMatcher(definingSupertype = "io.realm.RealmCo private const val MESSAGE = "Make sure using an unencrypted database is safe here." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6291") class UnencryptedDatabaseOnMobileCheck : AbstractCheck() { override fun visitCallExpression(callExpression: KtCallExpression, kotlinFileContext: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedFilesInMobileApplicationsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedFilesInMobileApplicationsCheck.kt index 80618d8e7..b0b05087e 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedFilesInMobileApplicationsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnencryptedFilesInMobileApplicationsCheck.kt @@ -26,6 +26,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val MESSAGE = "Make sure using unencrypted files is safe here." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6300") class UnencryptedFilesInMobileApplicationsCheck : CallAbstractCheck() { override val functionsToVisit = setOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnicodeAwareCharClassesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnicodeAwareCharClassesCheck.kt index 9681bfe4d..5de6a08e3 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnicodeAwareCharClassesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnicodeAwareCharClassesCheck.kt @@ -26,6 +26,7 @@ import org.sonarsource.kotlin.api.regex.PATTERN_COMPILE_MATCHER import org.sonarsource.kotlin.api.regex.RegexContext import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5867") class UnicodeAwareCharClassesCheck : AbstractRegexCheck() { override fun visitRegex( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt index 0debea09f..a72ca4424 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnnecessaryImportsCheck.kt @@ -54,6 +54,7 @@ private const val MESSAGE_REDUNDANT = "Remove this redundant import." private val DELEGATES_IMPORTED_NAMES = setOf("getValue", "setValue", "provideDelegate") private val ARRAY_ACCESS_IMPORTED_NAMES = setOf("get", "set") +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1128") class UnnecessaryImportsCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt index 279cfc6ac..103a27bf2 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableHashSaltCheck.kt @@ -49,6 +49,7 @@ private val matcherSaltIndexMap = mapOf( ConstructorMatcher("$SPECS_PACKAGE.$PARAMETER_SPEC_FUN_NAME") to 0, ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2053") class UnpredictableHashSaltCheck : CallAbstractCheck() { override val functionsToVisit = matcherSaltIndexMap.keys diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt index 89cc0cb07..37da051b6 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnpredictableSecureRandomSaltCheck.kt @@ -37,6 +37,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private const val MESSAGE = "Change this seed value to something unpredictable, or remove the seed." private const val SECURE_RANDOM = "java.security.SecureRandom" +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4347") class UnpredictableSecureRandomSaltCheck : CallAbstractCheck() { override val functionsToVisit = listOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnsuitedFindFunctionWithNullComparisonCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnsuitedFindFunctionWithNullComparisonCheck.kt index 6dc613795..e5c6dcf4a 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnsuitedFindFunctionWithNullComparisonCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnsuitedFindFunctionWithNullComparisonCheck.kt @@ -42,6 +42,7 @@ import org.sonarsource.kotlin.api.reporting.message * * The rule suggests to replace the pattern with `any(predicate)`, `none(predicate)`, and `contains(element)` depending on the case. */ +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6528") class UnsuitedFindFunctionWithNullComparisonCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt index c19251852..051a9c108 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedDeferredResultCheck.kt @@ -24,6 +24,7 @@ import org.sonarsource.kotlin.api.checks.DEFERRED_FQN import org.sonarsource.kotlin.api.checks.expressionTypeFqn import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6315") class UnusedDeferredResultCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedLocalVariableCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedLocalVariableCheck.kt index cd09f0366..051d9ed9d 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedLocalVariableCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedLocalVariableCheck.kt @@ -25,6 +25,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.getVariableType import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1481") class UnusedLocalVariableCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt index 2d3981011..d7f2c6eff 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UnusedPrivateMethodCheck.kt @@ -46,6 +46,7 @@ private val COMMON_ANNOTATIONS = listOf( "kotlin.jvm.Throws", ) +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S1144") class UnusedPrivateMethodCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessAssignmentsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessAssignmentsCheck.kt index c055857ae..8a2905028 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessAssignmentsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessAssignmentsCheck.kt @@ -23,6 +23,7 @@ import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6615") class UselessAssignmentsCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessIncrementCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessIncrementCheck.kt index ba7e0adb2..8a67b1ab1 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessIncrementCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessIncrementCheck.kt @@ -30,6 +30,7 @@ import org.sonarsource.kotlin.api.frontend.KotlinFileContext private val POSTFIX_INCREMENT_OPERATORS = listOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) private const val MESSAGE = "Remove this increment or correct the code not to waste it." +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S2123") class UselessIncrementCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt index 5940ef517..b6f00fd5d 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/UselessNullCheckCheck.kt @@ -46,6 +46,7 @@ private val NON_NULL_CHECK_FUNS = FunMatcher("kotlin") { withNames("requireNotNull", "checkNotNull") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6619") class UselessNullCheckCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt index 02c1e2df0..ace6f525b 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VarShouldBeValCheck.kt @@ -40,6 +40,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.frontend.KotlinFileContext import org.sonarsource.kotlin.api.reporting.message +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S3353") class VarShouldBeValCheck : AbstractCheck() { override fun visitKtFile(file: KtFile, data: KotlinFileContext) { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt index 3c00b9151..04db7729c 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VerifiedServerHostnamesCheck.kt @@ -28,6 +28,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S5527") class VerifiedServerHostnamesCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt index 10179c08f..30a0ef390 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ViewModelSuspendingFunctionsCheck.kt @@ -28,6 +28,7 @@ import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.suspendModifier import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6313") class ViewModelSuspendingFunctionsCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt index 7fe77c3f8..5cc419924 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/VoidShouldBeUnitCheck.kt @@ -43,6 +43,7 @@ private val message = message { +"." } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6508") class VoidShouldBeUnitCheck : AbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt index 9da68bc9a..34d7e4072 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WeakSSLContextCheck.kt @@ -32,6 +32,7 @@ import org.sonarsource.kotlin.api.reporting.SecondaryLocation import org.sonarsource.kotlin.api.reporting.KotlinTextRanges.textRange import org.sonarsource.kotlin.api.frontend.KotlinFileContext +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4423") class WeakSSLContextCheck : AbstractCheck() { private val WEAK_FOR_OK_HTTP = setOf( diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewJavaScriptSupportCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewJavaScriptSupportCheck.kt index f60d12e8d..9e95210c3 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewJavaScriptSupportCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewJavaScriptSupportCheck.kt @@ -34,6 +34,7 @@ private const val MESSAGE = "Make sure that enabling JavaScript support is safe private val ANDROID_SET_JAVASCRIPT_ENABLED = FunMatcher(definingSupertype = "android.webkit.WebSettings", name = "setJavaScriptEnabled") { withArguments("kotlin.Boolean") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6362") class WebViewJavaScriptSupportCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewsFileAccessCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewsFileAccessCheck.kt index b37e921f7..9f2436c78 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewsFileAccessCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/WebViewsFileAccessCheck.kt @@ -49,6 +49,7 @@ private val ANDROID_FILE_ACCESS_MATCHER = FunMatcher(definingSupertype = "androi withArguments("kotlin.Boolean") } +@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S6363") class WebViewsFileAccessCheck : CallAbstractCheck() { diff --git a/sonar-kotlin-checks/src/test/java/org/sonarsource/kotlin/checks/CheckTest.kt b/sonar-kotlin-checks/src/test/java/org/sonarsource/kotlin/checks/CheckTest.kt index 529c758a5..337cb2c39 100644 --- a/sonar-kotlin-checks/src/test/java/org/sonarsource/kotlin/checks/CheckTest.kt +++ b/sonar-kotlin-checks/src/test/java/org/sonarsource/kotlin/checks/CheckTest.kt @@ -17,8 +17,10 @@ package org.sonarsource.kotlin.checks import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.DisabledIf import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.testapi.KotlinVerifier +import kotlin.reflect.full.hasAnnotation private const val TEST_FILE_POSTFIX = "Sample.kt" @@ -31,8 +33,22 @@ abstract class CheckTest( ) { protected val checkName = check::class.java.simpleName + private fun k1only() = check::class.hasAnnotation() + + @Test + @DisabledIf("k1only") + fun `with k2 semantics`() { + KotlinVerifier(check) { + this.useK2 = true + this.fileName = sampleFileSemantics ?: "$checkName$TEST_FILE_POSTFIX" + this@CheckTest.classpath?.let { this.classpath = it } + this@CheckTest.dependencies?.let { this.deps = it } + this.isAndroid = this@CheckTest.isAndroid + }.verify() + } + @Test - fun `with semantics`() { + fun `with k1 semantics`() { KotlinVerifier(check) { this.fileName = sampleFileSemantics ?: "$checkName$TEST_FILE_POSTFIX" this@CheckTest.classpath?.let { this.classpath = it } diff --git a/sonar-kotlin-gradle/src/main/java/org/sonarsource/kotlin/gradle/KotlinGradleSensor.kt b/sonar-kotlin-gradle/src/main/java/org/sonarsource/kotlin/gradle/KotlinGradleSensor.kt index 0367c9270..23ddca763 100644 --- a/sonar-kotlin-gradle/src/main/java/org/sonarsource/kotlin/gradle/KotlinGradleSensor.kt +++ b/sonar-kotlin-gradle/src/main/java/org/sonarsource/kotlin/gradle/KotlinGradleSensor.kt @@ -59,6 +59,7 @@ class KotlinGradleSensor( sensorContext, filesToAnalyze, progressReport, listOf(KtChecksVisitor(checks)), filenames, LOG ) { override val bindingContext: BindingContext = BindingContext.EMPTY + override val doResolve: Boolean = false } override fun getFilesToAnalyse(sensorContext: SensorContext): Iterable { diff --git a/sonar-kotlin-plugin/build.gradle.kts b/sonar-kotlin-plugin/build.gradle.kts index 82b00df9b..b9703ce15 100644 --- a/sonar-kotlin-plugin/build.gradle.kts +++ b/sonar-kotlin-plugin/build.gradle.kts @@ -96,8 +96,14 @@ tasks.shadowJar { exclude("META-INF/native/**/*jansi*") exclude("org/jline/**") exclude("net/jpountz/**") + dependencies { + // include only K1, and exclude K2 for the time being + exclude(dependency("org.jetbrains.kotlin:analysis-api-k2-for-ide")) + exclude(dependency("org.jetbrains.kotlin:low-level-api-fir-for-ide")) + exclude(dependency("org.jetbrains.kotlin:symbol-light-classes-for-ide")) + } doLast { - enforceJarSizeAndCheckContent(shadowJar.get().archiveFile.get().asFile, 37_500_000L, 38_000_000L) + enforceJarSizeAndCheckContent(shadowJar.get().archiveFile.get().asFile, 45_800_000L, 46_200_000L) } } diff --git a/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/KotlinSensor.kt b/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/KotlinSensor.kt index c3f3210b2..c78e192d2 100644 --- a/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/KotlinSensor.kt +++ b/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/KotlinSensor.kt @@ -85,6 +85,8 @@ class KotlinSensor( BindingContext.EMPTY } } + + override val doResolve: Boolean = true } private fun visitors(sensorContext: SensorContext): List = diff --git a/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimization.java b/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimization.java index 939e9fb72..ed9bfb37f 100644 --- a/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimization.java +++ b/sonar-kotlin-plugin/src/main/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimization.java @@ -35,6 +35,18 @@ public class WorkaroundForJarMinimization { /** META-INF/services/org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper */ org.jetbrains.kotlin.codegen.signature.KotlinToJvmSignatureMapperImpl.class, + // META-INF/analysis-api/analysis-api-impl-base.xml + org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSourceWithSmartPointerFactory.class, + org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService.class, + org.jetbrains.kotlin.analysis.api.impl.base.projectStructure.KaBaseModuleProvider.class, + org.jetbrains.kotlin.analysis.api.platform.KotlinProjectMessageBusProvider.class, + org.jetbrains.kotlin.analysis.api.impl.base.permissions.KaBaseAnalysisPermissionChecker.class, + org.jetbrains.kotlin.analysis.api.impl.base.lifetime.KaBaseLifetimeTracker.class, + // META-INF/analysis-api/analysis-api-fe10.xml + org.jetbrains.kotlin.analysis.api.descriptors.KaFe10SessionProvider.class, + org.jetbrains.kotlin.references.fe10.base.KtFe10KotlinReferenceProviderContributor.class, + org.jetbrains.kotlin.analysis.api.descriptors.references.ReadWriteAccessCheckerDescriptorsImpl.class, + /** Used to have proper named groups behavior in regular expressions */ kotlin.internal.jdk8.JDK8PlatformImplementations.class ); diff --git a/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/KotlinSensorTest.kt b/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/KotlinSensorTest.kt index 78b0e6c27..3622534f8 100644 --- a/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/KotlinSensorTest.kt +++ b/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/KotlinSensorTest.kt @@ -220,11 +220,29 @@ internal class KotlinSensorTest : AbstractSensorTest() { assertThat(issues).hasSize(2) } + /** + * ``` + * java.lang.IllegalStateException: Resolution is not performed + * at org.jetbrains.kotlin.analysis.api.descriptors.CliFe10AnalysisFacade.orThrowResolutionNotPerformedError(CliFe10AnalysisFacade.kt:78) + * at org.jetbrains.kotlin.analysis.api.descriptors.CliFe10AnalysisFacade.getAnalysisContext(CliFe10AnalysisFacade.kt:52) + * at org.jetbrains.kotlin.analysis.api.descriptors.CliFe10AnalysisFacade.getAnalysisContext(CliFe10AnalysisFacade.kt:41) + * at org.jetbrains.kotlin.analysis.api.descriptors.KaFe10SessionProvider.getAnalysisSession(KaFe10SessionProvider.kt:24) + * at org.sonarsource.kotlin.api.visiting.KotlinFileVisitor.scan(KotlinFileVisitor.kt:48) + * ``` + * thrown by [org.jetbrains.kotlin.analysis.api.analyze] + */ @Test fun `Ensure compiler crashes during BindingContext generation don't crash engine`() { context.setCanSkipUnchangedFiles(false) executeAnalysisWithInvalidBindingContext() - assertThat(logTester.logs(Level.ERROR)).containsExactly("Could not generate binding context. Proceeding without semantics.") + assertThat(logTester.logs(Level.ERROR)).containsExactly( + "Could not generate binding context. Proceeding without semantics.", + "Cannot analyse 'file1.kt' with 'IssueSuppressionVisitor': Resolution is not performed", + "Cannot analyse 'file1.kt' with 'MetricVisitor': Resolution is not performed", + "Cannot analyse 'file1.kt' with 'KtChecksVisitor': Resolution is not performed", + "Cannot analyse 'file1.kt' with 'CopyPasteDetector': Resolution is not performed", + "Cannot analyse 'file1.kt' with 'SyntaxHighlighter': Resolution is not performed", + ) } @Test diff --git a/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimizationTest.kt b/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimizationTest.kt index 9449595c9..95b77e262 100644 --- a/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimizationTest.kt +++ b/sonar-kotlin-plugin/src/test/java/org/sonarsource/kotlin/plugin/linking/WorkaroundForJarMinimizationTest.kt @@ -22,6 +22,6 @@ import org.junit.jupiter.api.Test internal class WorkaroundForJarMinimizationTest { @Test fun minimizing_class_count() { - assertThat(WorkaroundForJarMinimization.CLASSES_TO_KEEP_WHEN_MINIMIZING_JAR).hasSize(7) + assertThat(WorkaroundForJarMinimization.CLASSES_TO_KEEP_WHEN_MINIMIZING_JAR).hasSize(16) } } diff --git a/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/KotlinVerifier.kt b/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/KotlinVerifier.kt index a9e569289..159ebfd9b 100644 --- a/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/KotlinVerifier.kt +++ b/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/KotlinVerifier.kt @@ -53,6 +53,7 @@ class KotlinVerifier(private val check: AbstractCheck) { var deps: List = getClassPath(DEFAULT_TEST_JARS_DIRECTORY) var isAndroid = false var customDiagnostics: List? = null + var useK2 = false fun verify() { verifyFile { @@ -70,10 +71,11 @@ class KotlinVerifier(private val check: AbstractCheck) { val isScriptFile = filePath.extension == "kts" val disposable = Disposer.newDisposable() - val environment = Environment(disposable, classpath + deps, LanguageVersion.LATEST_STABLE) + val environment = Environment(disposable, classpath + deps, LanguageVersion.LATEST_STABLE, useK2 = useK2) val converter = { content: String -> val inputFile = TestInputFileBuilder("moduleKey", filePath.fileName.pathString) .setCharset(StandardCharsets.UTF_8) + .setModuleBaseDir(baseDir) .initMetadata(content).build() if (isScriptFile) { diff --git a/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/TestUtils.kt b/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/TestUtils.kt index cbd6b693a..e1d430481 100644 --- a/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/TestUtils.kt +++ b/sonar-kotlin-test-api/src/main/java/org/sonarsource/kotlin/testapi/TestUtils.kt @@ -21,17 +21,34 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.sonar.api.batch.fs.InputFile // TODO: testapi should not depend on frontend module. import org.sonarsource.kotlin.api.frontend.Environment +import org.sonarsource.kotlin.api.frontend.KotlinFileSystem import org.sonarsource.kotlin.api.frontend.KotlinSyntaxStructure import org.sonarsource.kotlin.api.frontend.KotlinTree +import org.sonarsource.kotlin.api.frontend.KotlinVirtualFile import org.sonarsource.kotlin.api.frontend.RegexCache import org.sonarsource.kotlin.api.frontend.analyzeAndGetBindingContext +import org.sonarsource.kotlin.api.frontend.createK2AnalysisSession +import java.io.File fun kotlinTreeOf(content: String, environment: Environment, inputFile: InputFile, doResolve: Boolean = true, providedDiagnostics: List? = null): KotlinTree { + if (environment.useK2) { + val virtualFile = KotlinVirtualFile( + KotlinFileSystem(), + File(inputFile.uri().path), + content, + ) + environment.k2session = createK2AnalysisSession( + environment.disposable, + environment.configuration, + listOf(virtualFile), + ) + } + val (ktFile, document) = KotlinSyntaxStructure.of(content, environment, inputFile) - val bindingContext = if (doResolve) analyzeAndGetBindingContext( + val bindingContext = if (!environment.useK2 && doResolve) analyzeAndGetBindingContext( environment.env, listOf(ktFile), ) else BindingContext.EMPTY - return KotlinTree(ktFile, document, bindingContext, providedDiagnostics ?: bindingContext.diagnostics.noSuppression().toList(), RegexCache()) + return KotlinTree(ktFile, document, bindingContext, providedDiagnostics ?: bindingContext.diagnostics.noSuppression().toList(), RegexCache(), doResolve) }