Skip to content

Commit

Permalink
Merge branch 'master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Godin committed Nov 29, 2024
2 parents 6e903b3 + f44acf4 commit d41920b
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 62 deletions.
16 changes: 8 additions & 8 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -807,32 +807,32 @@
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-fe10-for-ide" version="2.0.21">
<artifact name="analysis-api-fe10-for-ide-2.0.21.jar">
<sha256 value="2ff6e25ce9d8b3bc43423d5552bbe6e3ba1e37f588601e3b651d240a06aec5d2" origin="Generated by Gradle"/>
<sha256 value="2ff6e25ce9d8b3bc43423d5552bbe6e3ba1e37f588601e3b651d240a06aec5d2" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-for-ide" version="2.0.21">
<artifact name="analysis-api-for-ide-2.0.21.jar">
<sha256 value="3a9436ea39d53eb6686557124a26a914747b1b87acf93fe93d88d8df3db9c467" origin="Generated by Gradle"/>
<sha256 value="3a9436ea39d53eb6686557124a26a914747b1b87acf93fe93d88d8df3db9c467" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-impl-base-for-ide" version="2.0.21">
<artifact name="analysis-api-impl-base-for-ide-2.0.21.jar">
<sha256 value="507088828a8cc64d727954ded1ba752fb9076d770578c41b892fb70c263af2d6" origin="Generated by Gradle"/>
<sha256 value="507088828a8cc64d727954ded1ba752fb9076d770578c41b892fb70c263af2d6" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-k2-for-ide" version="2.0.21">
<artifact name="analysis-api-k2-for-ide-2.0.21.jar">
<sha256 value="7bdd4d25d5ab7e2e79ff101ca1827ab67d4da3dfab69fd77ce5de37f1c5cdcb0" origin="Generated by Gradle"/>
<sha256 value="7bdd4d25d5ab7e2e79ff101ca1827ab67d4da3dfab69fd77ce5de37f1c5cdcb0" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-platform-interface-for-ide" version="2.0.21">
<artifact name="analysis-api-platform-interface-for-ide-2.0.21.jar">
<sha256 value="91f42f11a73ebd5de4c1c654abe1a5127568c30a3ef41ac72017fc3275fad56b" origin="Generated by Gradle"/>
<sha256 value="91f42f11a73ebd5de4c1c654abe1a5127568c30a3ef41ac72017fc3275fad56b" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="analysis-api-standalone-for-ide" version="2.0.21">
<artifact name="analysis-api-standalone-for-ide-2.0.21.jar">
<sha256 value="6045d797d9b64f238e13d75ea9b7de07ca76f8b7a7376a1ba0bde617c32ae2f7" origin="Generated by Gradle"/>
<sha256 value="6045d797d9b64f238e13d75ea9b7de07ca76f8b7a7376a1ba0bde617c32ae2f7" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-android-extensions" version="1.9.23">
Expand Down Expand Up @@ -1462,12 +1462,12 @@
</component>
<component group="org.jetbrains.kotlin" name="low-level-api-fir-for-ide" version="2.0.21">
<artifact name="low-level-api-fir-for-ide-2.0.21.jar">
<sha256 value="7ffc73a07642c6790ca94d46a70b8c77dd7087ed25de8a41a13edb7727641f5a" origin="Generated by Gradle"/>
<sha256 value="7ffc73a07642c6790ca94d46a70b8c77dd7087ed25de8a41a13edb7727641f5a" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="symbol-light-classes-for-ide" version="2.0.21">
<artifact name="symbol-light-classes-for-ide-2.0.21.jar">
<sha256 value="44db8c66d15b17062aaea60a18f193c4172bfd0057f84bc5f6ed5db8cfed26e6" origin="Generated by Gradle"/>
<sha256 value="44db8c66d15b17062aaea60a18f193c4172bfd0057f84bc5f6ed5db8cfed26e6" origin="Verified"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="atomicfu" version="0.16.2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ import org.jetbrains.kotlin.references.fe10.base.DummyKtFe10ReferenceResolutionH
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.
*/
@Deprecated("")
annotation class K1only(val comments: String = "")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ 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.StandaloneAnalysisAPISessionBuilder
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
Expand All @@ -38,7 +37,7 @@ import java.io.InputStream
import java.io.OutputStream

/**
* See also [StandaloneAnalysisAPISessionBuilder.buildKtModuleProviderByCompilerConfiguration]
* @see [org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISessionBuilder.buildKtModuleProviderByCompilerConfiguration]
*/
fun createK2AnalysisSession(
parentDisposable: Disposable,
Expand All @@ -64,7 +63,7 @@ fun createK2AnalysisSession(
libraryName = "library"
addBinaryRoots(compilerConfiguration.jvmClasspathRoots.map { it.toPath() })
})
compilerConfiguration.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome ->
compilerConfiguration[JVMConfigurationKeys.JDK_HOME]?.let { jdkHome ->
addRegularDependency(buildKtSdkModule {
this.platform = platform
addBinaryRootsFromJdkHome(jdkHome.toPath(), isJre = false)
Expand All @@ -77,7 +76,9 @@ fun createK2AnalysisSession(
}

class KotlinFileSystem : CoreLocalFileSystem() {
// TODO null if file does not exist
/**
* TODO return null if file does not exist - see [CoreLocalFileSystem.findFileByNioFile]
*/
override fun findFileByPath(path: String): VirtualFile? =
KotlinVirtualFile(this, File(path))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ 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<Diagnostic>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ data class KotlinSyntaxStructure(val ktFile: KtFile, val document: Document, val

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
environment.k2session!!.modulesWithFiles.values.first().find {
it.virtualFile.path == inputFilePath
} as KtFile
} else
environment.ktPsiFactory.createFile(inputFile.uri().path, normalizeEol(content))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@
@Deprecated(forRemoval = true)
final class KtModuleProviderByCompilerConfiguration {

@SuppressWarnings("KotlinInternalInJava")
public static KotlinStaticProjectStructureProvider build(
KotlinCoreProjectEnvironment kotlinCoreProjectEnvironment,
CompilerConfiguration compilerConfig,
List<KtFile> ktFiles
) {
return org.jetbrains.kotlin.analysis.project.structure.impl
.KaModuleUtilsKt.buildKtModuleProviderByCompilerConfiguration(
kotlinCoreProjectEnvironment,
compilerConfig,
ktFiles
);
}
@SuppressWarnings("KotlinInternalInJava")
static KotlinStaticProjectStructureProvider build(
KotlinCoreProjectEnvironment kotlinCoreProjectEnvironment,
CompilerConfiguration compilerConfig,
List<KtFile> ktFiles
) {
return org.jetbrains.kotlin.analysis.project.structure.impl
.KaModuleUtilsKt.buildKtModuleProviderByCompilerConfiguration(
kotlinCoreProjectEnvironment,
compilerConfig,
ktFiles
);
}

private KtModuleProviderByCompilerConfiguration() {
}
private KtModuleProviderByCompilerConfiguration() {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,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

@Deprecated("use withKaSession instead", ReplaceWith("withKaSession(action)"))
inline fun <R> analyze(action: KaSession.() -> R) = withKaSession(action)

/**
* Executes the given [action] in a [KaSession] context
* providing access to [Kotlin Analysis API](https://kotl.in/analysis-api).
*/
inline fun <R> withKaSession(action: KaSession.() -> R): R = action(kaSession!!)

@PublishedApi
internal var kaSession: KaSession? = null

inline fun <R> analyze(action: KaSession.() -> R): R = action(kaSession!!)
/**
* 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) {
val kotlinFileContext =
KotlinFileContext(fileContext, root.psiFile, root.bindingContext, root.diagnostics, root.regexCache)
if (!root.doResolve) {
visit(kotlinFileContext)
} else {
check(kaSession == null)
try {
analyze(root.psiFile) {
kaSession = this
visit(kotlinFileContext)
}
} finally {
kaSession = null
if (root.doResolve) {
kaSession(root.psiFile) {
visit(kotlinFileContext)
}
} else {
visit(kotlinFileContext)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -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<KtIsExpression>()!!.expressionType.toString())
.isEqualTo("kotlin/Boolean")
assertThat(ktFile.findDescendantOfType<KtDotQualifiedExpression>()!!.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<KtIsExpression>()!!.expressionType.toString())
.isEqualTo("kotlin/Boolean")
assertThat(ktFile.findDescendantOfType<KtDotQualifiedExpression>()!!.expressionType.toString())
.isEqualTo("kotlin/Int")
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ abstract class CheckTest(
}

@Test
fun `with semantics`() {
fun `with k1 semantics`() {
KotlinVerifier(check) {
this.fileName = sampleFileSemantics ?: "$checkName$TEST_FILE_POSTFIX"
this@CheckTest.classpath?.let { this.classpath = it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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-bsase.xml
// 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,21 +223,26 @@ internal class KotlinSensorTest : AbstractSensorTest() {
/**
* ```
* 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:57)
* 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)
* ```
*
* TODO try to mock analyzeDeclarations in TopDownAnalyzerFacadeForJVM which is after analysisHandlerExtensions
* thrown by [org.jetbrains.kotlin.analysis.api.analyze]
*/
@org.junit.jupiter.api.Disabled
@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +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,
useK2 = useK2,
)
val environment = Environment(disposable, classpath + deps, LanguageVersion.LATEST_STABLE, useK2 = useK2)
val converter = { content: String ->
val inputFile = TestInputFileBuilder("moduleKey", filePath.fileName.pathString)
.setModuleBaseDir(filePath.parent) // otherwise projectKey "moduleKey" leaks into absolutePath
.setCharset(StandardCharsets.UTF_8)
.setModuleBaseDir(baseDir)
.initMetadata(content).build()

if (isScriptFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ fun kotlinTreeOf(content: String, environment: Environment, inputFile: InputFile
environment.k2session = createK2AnalysisSession(
environment.disposable,
environment.configuration,
listOf(virtualFile)
listOf(virtualFile),
)
}

Expand Down

0 comments on commit d41920b

Please sign in to comment.