diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/Helpers.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/Helpers.kt new file mode 100644 index 00000000000..815dc9b3892 --- /dev/null +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/Helpers.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.js + +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.psi.KtFile + +fun checkKotlinPackageUsageForPsi(configuration: CompilerConfiguration, files: Collection) = + org.jetbrains.kotlin.cli.common.checkKotlinPackageUsageForPsi(configuration, files) diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index 184cf69cb88..052ee2362ef 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -220,7 +220,7 @@ public class K2JSCompiler extends CLICompiler { environmentForJS.getConfiguration().put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.getRenderInternalDiagnosticNames()); - if (!UtilsKt.checkKotlinPackageUsage(environmentForJS.getConfiguration(), sourcesFiles)) return ExitCode.COMPILATION_ERROR; + if (!HelpersKt.checkKotlinPackageUsageForPsi(environmentForJS.getConfiguration(), sourcesFiles)) return ExitCode.COMPILATION_ERROR; if (arguments.getOutputFile() == null) { messageCollector.report(ERROR, "Specify output file via -output", null); diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 07a0d57f5ec..c089f361435 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -208,7 +208,7 @@ class K2JsIrCompiler : CLICompiler() { Disposer.register(rootDisposable, zipAccessor) configurationJs.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, zipAccessor) - if (!checkKotlinPackageUsage(environmentForJS.configuration, sourcesFiles)) return COMPILATION_ERROR + if (!checkKotlinPackageUsageForPsi(environmentForJS.configuration, sourcesFiles)) return COMPILATION_ERROR val outputDirPath = arguments.outputDir val outputName = arguments.moduleName diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/utils.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/utils.kt index 96cd10ea6f7..21590c397ed 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/utils.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/utils.kt @@ -16,15 +16,18 @@ package org.jetbrains.kotlin.cli.common +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.KtSourceFileLinesMapping import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageUtil +import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.IncrementalCompilation +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.packageFqName import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.isSubpackageOf import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.text import org.jetbrains.kotlin.util.Logger import java.io.File import kotlin.system.exitProcess @@ -37,17 +40,23 @@ fun incrementalCompilationIsEnabledForJs(arguments: CommonCompilerArguments): Bo return arguments.incrementalCompilation ?: IncrementalCompilation.isEnabledForJs() } -fun checkKotlinPackageUsage(configuration: CompilerConfiguration, files: Collection, messageCollector: MessageCollector): Boolean { +fun checkKotlinPackageUsage( + configuration: CompilerConfiguration, + files: Collection, + messageCollector: MessageCollector, + getPackage: (F) -> FqName, + getMessageLocation: (F) -> CompilerMessageSourceLocation?, +): Boolean { if (configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE)) { return true } val kotlinPackage = FqName("kotlin") for (file in files) { - if (file.packageFqName.isSubpackageOf(kotlinPackage)) { + if (getPackage(file).isSubpackageOf(kotlinPackage)) { messageCollector.report( CompilerMessageSeverity.ERROR, "Only the Kotlin standard library is allowed to use the 'kotlin' package", - MessageUtil.psiElementToMessageLocation(file.packageDirective!!) + getMessageLocation(file), ) return false } @@ -55,8 +64,46 @@ fun checkKotlinPackageUsage(configuration: CompilerConfiguration, files: Collect return true } -fun checkKotlinPackageUsage(configuration: CompilerConfiguration, files: Collection): Boolean = - checkKotlinPackageUsage(configuration, files, configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)) +private val CompilerConfiguration.messageCollector: MessageCollector + get() = get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE) + +fun checkKotlinPackageUsageForPsi( + configuration: CompilerConfiguration, + files: Collection, + messageCollector: MessageCollector = configuration.messageCollector, +) = + checkKotlinPackageUsage( + configuration, files, messageCollector, + getPackage = { it.packageFqName }, + getMessageLocation = { MessageUtil.psiElementToMessageLocation(it.packageDirective!!) }, + ) + +fun checkKotlinPackageUsageForLightTree( + configuration: CompilerConfiguration, + files: Collection, + messageCollector: MessageCollector = configuration.messageCollector, +) = + checkKotlinPackageUsage( + configuration, files, messageCollector, + getPackage = { it.packageFqName }, + getMessageLocation = { it.packageDirective.source?.getLocationWithin(it) }, + ) + +private fun KtSourceElement.getLocationWithin(file: FirFile): CompilerMessageLocationWithRange? { + val sourceFile = file.sourceFile ?: return null + val (startLine, startColumn) = file.getLineAndColumnStartingWithOnesAt(startOffset) ?: return null + val (endLine, endColumn) = file.getLineAndColumnStartingWithOnesAt(endOffset) ?: return null + return CompilerMessageLocationWithRange.create(sourceFile.path, startLine, startColumn, endLine, endColumn, text?.toString()) +} + +private fun FirFile.getLineAndColumnStartingWithOnesAt(offset: Int?): Pair? { + return offset?.let { sourceFileLinesMapping?.getLineAndColumnByOffsetStartingWithOnes(it) } +} + +private fun KtSourceFileLinesMapping.getLineAndColumnByOffsetStartingWithOnes(startOffset: Int): Pair { + val (line, column) = getLineAndColumnByOffset(startOffset) + return line + 1 to column + 1 +} fun getLibraryFromHome( paths: PathProvider?, diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt index 0e557e605a8..530878a21d1 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt @@ -137,7 +137,7 @@ object FirKotlinToJvmBytecodeCompiler { performanceManager?.notifyAnalysisStarted() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() - if (!checkKotlinPackageUsage(moduleConfiguration, allSources)) return null + if (!checkKotlinPackageUsageForPsi(moduleConfiguration, allSources)) return null val renderDiagnosticNames = moduleConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index aba6e9964a4..1a244f76dab 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -15,7 +15,7 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage +import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsageForPsi import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.fir.FirDiagnosticsCompilerResultsReporter import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport @@ -107,7 +107,7 @@ object KotlinToJVMBytecodeCompiler { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() val ktFiles = module.getSourceFiles(environment.getSourceFiles(), localFileSystem, chunk.size > 1, buildFile) - if (!checkKotlinPackageUsage(environment.configuration, ktFiles)) return false + if (!checkKotlinPackageUsageForPsi(environment.configuration, ktFiles)) return false val moduleConfiguration = projectConfiguration.applyModuleProperties(module, buildFile) val backendInput = codegenFactory.getModuleChunkBackendInput(wholeBackendInput, ktFiles) @@ -133,7 +133,7 @@ object KotlinToJVMBytecodeCompiler { moduleVisibilityManager.addFriendPath(path) } - if (!checkKotlinPackageUsage(environment.configuration, environment.getSourceFiles())) return false + if (!checkKotlinPackageUsageForPsi(environment.configuration, environment.getSourceFiles())) return false val generationState = analyzeAndGenerate(environment) ?: return false diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/pipeline/compilerPipeline.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/pipeline/compilerPipeline.kt index 86213b264c1..28aac1ece8d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/pipeline/compilerPipeline.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/pipeline/compilerPipeline.kt @@ -117,6 +117,10 @@ fun compileModulesUsingFrontendIrAndLightTree( performanceManager ) + if (!checkKotlinPackageUsageForLightTree(moduleConfiguration, analysisResults.outputs.flatMap { it.fir })) { + return false + } + performanceManager?.notifyAnalysisFinished() // TODO: consider what to do if many modules has main classes diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt index 0dadfa2be1f..2b4f5f02be1 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt @@ -31,7 +31,6 @@ import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.Services -import org.jetbrains.kotlin.config.getModuleNameForSource import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil @@ -115,7 +114,7 @@ class K2MetadataCompiler : CLICompiler() { return ExitCode.COMPILATION_ERROR } - checkKotlinPackageUsage(environment.configuration, environment.getSourceFiles()) + checkKotlinPackageUsageForPsi(environment.configuration, environment.getSourceFiles()) try { val useFir = configuration.getBoolean(CommonConfigurationKeys.USE_FIR) diff --git a/compiler/testData/cli/jvm/forbidKotlinPackage.kt b/compiler/testData/cli/jvm/forbidKotlinPackage.kt new file mode 100644 index 00000000000..04561ef6d08 --- /dev/null +++ b/compiler/testData/cli/jvm/forbidKotlinPackage.kt @@ -0,0 +1,6 @@ +// FIR_IDENTICAL +// ISSUE: KT-57803 + +package kotlin.internal + +fun main(args: Array) {} diff --git a/compiler/testData/cli/jvm/forbidKotlinPackageK1.args b/compiler/testData/cli/jvm/forbidKotlinPackageK1.args new file mode 100644 index 00000000000..552f592d6ec --- /dev/null +++ b/compiler/testData/cli/jvm/forbidKotlinPackageK1.args @@ -0,0 +1,3 @@ +$TESTDATA_DIR$/forbidKotlinPackage.kt +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/forbidKotlinPackageK1.out b/compiler/testData/cli/jvm/forbidKotlinPackageK1.out new file mode 100644 index 00000000000..05d8a508785 --- /dev/null +++ b/compiler/testData/cli/jvm/forbidKotlinPackageK1.out @@ -0,0 +1,4 @@ +compiler/testData/cli/jvm/forbidKotlinPackage.kt:4:1: error: only the Kotlin standard library is allowed to use the 'kotlin' package +package kotlin.internal +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/forbidKotlinPackageK2.args b/compiler/testData/cli/jvm/forbidKotlinPackageK2.args new file mode 100644 index 00000000000..765f506e93a --- /dev/null +++ b/compiler/testData/cli/jvm/forbidKotlinPackageK2.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/forbidKotlinPackage.kt +-language-version +2.0 +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/forbidKotlinPackageK2.out b/compiler/testData/cli/jvm/forbidKotlinPackageK2.out new file mode 100644 index 00000000000..13971df39bd --- /dev/null +++ b/compiler/testData/cli/jvm/forbidKotlinPackageK2.out @@ -0,0 +1,5 @@ +warning: language version 2.0 is experimental, there are no backwards compatibility guarantees for new language and library features +compiler/testData/cli/jvm/forbidKotlinPackage.kt:4:1: error: only the Kotlin standard library is allowed to use the 'kotlin' package +package kotlin.internal +^ +COMPILATION_ERROR diff --git a/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java index 12247798afa..a4f51ff2d8e 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -595,6 +595,16 @@ public class CliTestGenerated extends AbstractCliTest { runTest("compiler/testData/cli/jvm/flagAllowingResultAsReturnType.args"); } + @TestMetadata("forbidKotlinPackageK1.args") + public void testForbidKotlinPackageK1() throws Exception { + runTest("compiler/testData/cli/jvm/forbidKotlinPackageK1.args"); + } + + @TestMetadata("forbidKotlinPackageK2.args") + public void testForbidKotlinPackageK2() throws Exception { + runTest("compiler/testData/cli/jvm/forbidKotlinPackageK2.args"); + } + @TestMetadata("functionReferenceWithDefaultValuesFeatureIsEnabledWithNewInference.args") public void testFunctionReferenceWithDefaultValuesFeatureIsEnabledWithNewInference() throws Exception { runTest("compiler/testData/cli/jvm/functionReferenceWithDefaultValuesFeatureIsEnabledWithNewInference.args"); diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt index 471c0818aca..920ee52f1f0 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensionsImpl import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage +import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsageForPsi import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.MessageCollector @@ -95,7 +95,7 @@ open class KJvmReplCompilerBase( if (firstFailure != null) return firstFailure - checkKotlinPackageUsage(context.environment.configuration, sourceFiles, messageCollector) + checkKotlinPackageUsageForPsi(context.environment.configuration, sourceFiles, messageCollector) if (messageCollector.hasErrors()) return failure(messageCollector) diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/ScriptJvmCompilerImpls.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/ScriptJvmCompilerImpls.kt index 05d686563cc..e6e47e4a55e 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/ScriptJvmCompilerImpls.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/ScriptJvmCompilerImpls.kt @@ -139,7 +139,7 @@ private fun compileImpl( messageCollector ) - checkKotlinPackageUsage(context.environment.configuration, sourceFiles, messageCollector) + checkKotlinPackageUsageForPsi(context.environment.configuration, sourceFiles, messageCollector) if (messageCollector.hasErrors() || sourceDependencies.any { it.sourceDependencies is ResultWithDiagnostics.Failure }) { return failure(messageCollector)