diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/script/CliScriptReportSink.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/script/CliScriptReportSink.kt new file mode 100644 index 00000000000..587e3e1b042 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/script/CliScriptReportSink.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli.common.script + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.script.ScriptReportSink +import kotlin.script.dependencies.ScriptReport + +class CliScriptReportSink(private val messageCollector: MessageCollector) : ScriptReportSink { + override fun attachReports(scriptFile: VirtualFile, reports: List) { + reports.forEach { + messageCollector.report(it.severity.convertSeverity(), it.message, location(scriptFile, it.position)) + } + } + + private fun location(scriptFile: VirtualFile, position: ScriptReport.Position?): CompilerMessageLocation? { + if (position == null) return CompilerMessageLocation.create(scriptFile.path) + + return CompilerMessageLocation.create(scriptFile.path, position.startLine, position.startColumn, null) + } + + private fun ScriptReport.Severity.convertSeverity(): CompilerMessageSeverity = when(this) { + ScriptReport.Severity.ERROR -> CompilerMessageSeverity.ERROR + ScriptReport.Severity.WARNING -> CompilerMessageSeverity.WARNING + ScriptReport.Severity.INFO -> CompilerMessageSeverity.INFO + ScriptReport.Severity.DEBUG -> CompilerMessageSeverity.LOGGING + } +} + diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index bd2af04ef33..380a4b535d5 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -73,6 +73,9 @@ import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PRO import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.common.script.CliScriptReportSink +import org.jetbrains.kotlin.cli.common.script.KotlinScriptExternalImportsProviderImpl import org.jetbrains.kotlin.cli.common.toBooleanLenient import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker import org.jetbrains.kotlin.cli.jvm.config.* @@ -104,7 +107,7 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFact import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider import org.jetbrains.kotlin.script.KotlinScriptExternalImportsProvider -import org.jetbrains.kotlin.cli.common.script.KotlinScriptExternalImportsProviderImpl +import org.jetbrains.kotlin.script.ScriptReportSink import org.jetbrains.kotlin.utils.PathUtil import java.io.File @@ -173,7 +176,8 @@ class KotlinCoreEnvironment private constructor( project.registerService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES)) registerProjectServicesForCLI(projectEnvironment) - registerProjectServices(projectEnvironment) + val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + registerProjectServices(projectEnvironment, messageCollector) sourceFiles += CompileEnvironmentUtil.getKtFiles(project, getSourceRootsCheckingForDuplicates(), this.configuration, { message -> @@ -193,8 +197,6 @@ class KotlinCoreEnvironment private constructor( } } - val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - classpathRootsResolver = ClasspathRootsResolver( PsiManager.getInstance(project), messageCollector, configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES), @@ -517,13 +519,16 @@ class KotlinCoreEnvironment private constructor( // made public for Upsource @JvmStatic - fun registerProjectServices(projectEnvironment: JavaCoreProjectEnvironment) { + fun registerProjectServices(projectEnvironment: JavaCoreProjectEnvironment, messageCollector: MessageCollector?) { with (projectEnvironment.project) { val kotlinScriptDefinitionProvider = KotlinScriptDefinitionProvider() registerService(KotlinScriptDefinitionProvider::class.java, kotlinScriptDefinitionProvider) registerService(KotlinScriptExternalImportsProvider::class.java, KotlinScriptExternalImportsProviderImpl(projectEnvironment.project, kotlinScriptDefinitionProvider)) registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this)) registerService(KtLightClassForFacade.FacadeStubCache::class.java, KtLightClassForFacade.FacadeStubCache(this)) + if (messageCollector != null) { + registerService(ScriptReportSink::class.java, CliScriptReportSink(messageCollector)) + } } } diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderBase.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderBase.kt index 2f6c19e3333..3eaa829434a 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderBase.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderBase.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.script +import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile @@ -27,7 +28,7 @@ import kotlin.reflect.KClass import kotlin.script.dependencies.ScriptContents import kotlin.script.dependencies.ScriptDependencies -abstract class KotlinScriptExternalImportsProviderBase(private val project: Project): KotlinScriptExternalImportsProvider { +abstract class KotlinScriptExternalImportsProviderBase(private val project: Project) : KotlinScriptExternalImportsProvider { fun getScriptContents(scriptDefinition: KotlinScriptDefinition, file: VirtualFile) = BasicScriptContents(file, getAnnotations = { loadAnnotations(scriptDefinition, file) }) @@ -61,10 +62,12 @@ abstract class KotlinScriptExternalImportsProviderBase(private val project: Proj file: VirtualFile ): ScriptDependencies? { val scriptContents = getScriptContents(scriptDef, file) - return scriptDef.dependencyResolver.resolve( + val result = scriptDef.dependencyResolver.resolve( scriptContents, (scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.environment ?: emptyMap() - ).dependencies + ) + ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) + return result.dependencies } } diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptReportSink.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptReportSink.kt new file mode 100644 index 00000000000..3711109df0f --- /dev/null +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptReportSink.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.script + +import com.intellij.openapi.vfs.VirtualFile +import kotlin.script.dependencies.ScriptReport + +interface ScriptReportSink { + fun attachReports(scriptFile: VirtualFile, reports: List) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerApiTest.kt b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerApiTest.kt index 5113bd98c33..7aedf90f6c4 100644 --- a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerApiTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerApiTest.kt @@ -200,9 +200,10 @@ class TestMessageCollector : MessageCollector { override fun hasErrors(): Boolean = messages.any { it.severity == CompilerMessageSeverity.EXCEPTION || it.severity == CompilerMessageSeverity.ERROR } } -fun TestMessageCollector.assertHasMessage(msg: String) { - assert(messages.any { it.message.contains(msg) }) { - "Expecting message \"$msg\", actual:\n${messages.joinToString("\n") { it.message }}" +fun TestMessageCollector.assertHasMessage(msg: String, desiredSeverity: CompilerMessageSeverity? = null) { + assert(messages.any { it.message.contains(msg) && (desiredSeverity == null || it.severity == desiredSeverity) }) { + "Expecting message \"$msg\" with severity ${desiredSeverity?.toString() ?: "Any"}, actual:\n" + + messages.joinToString("\n") { it.severity.toString() + ": " + it.message } } } diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt index 18860eba7af..cb84ff034f2 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt @@ -25,6 +25,8 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.addKotlinSourceRoot +import org.jetbrains.kotlin.daemon.TestMessageCollector +import org.jetbrains.kotlin.daemon.assertHasMessage import org.jetbrains.kotlin.daemon.toFile import org.jetbrains.kotlin.script.InvalidScriptResolverAnnotation import org.jetbrains.kotlin.script.KotlinScriptDefinition @@ -236,6 +238,17 @@ class ScriptTemplateTest { } } + @Test + fun testScriptErrorReporting() { + val messageCollector = TestMessageCollector() + compileScript("fib.kts", ScriptReportingErrors::class, messageCollector = messageCollector) + + messageCollector.assertHasMessage("error", desiredSeverity = CompilerMessageSeverity.ERROR) + messageCollector.assertHasMessage("warning", desiredSeverity = CompilerMessageSeverity.WARNING) + messageCollector.assertHasMessage("info", desiredSeverity = CompilerMessageSeverity.INFO) + messageCollector.assertHasMessage("debug", desiredSeverity = CompilerMessageSeverity.LOGGING) + } + @Test fun testSmokeScriptException() { val aClass = compileScript("smoke_exception.kts", ScriptWithArrayParam::class) @@ -270,24 +283,20 @@ class ScriptTemplateTest { scriptTemplate: KClass, environment: Map? = null, runIsolated: Boolean = true, - suppressOutput: Boolean = false, + messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false), includeKotlinRuntime: Boolean = true ): Class<*>? = compileScriptImpl("compiler/testData/script/" + scriptPath, KotlinScriptDefinitionFromAnnotatedTemplate( scriptTemplate, null, null, environment - ), runIsolated, suppressOutput, includeKotlinRuntime) + ), runIsolated, messageCollector, includeKotlinRuntime) private fun compileScriptImpl( scriptPath: String, scriptDefinition: KotlinScriptDefinition, runIsolated: Boolean, - suppressOutput: Boolean, + messageCollector: MessageCollector, includeKotlinRuntime: Boolean ): Class<*>? { - val messageCollector = - if (suppressOutput) MessageCollector.NONE - else PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false) - val rootDisposable = Disposer.newDisposable() try { val configuration = KotlinTestUtils.newConfiguration(if (includeKotlinRuntime) ConfigurationKind.ALL else ConfigurationKind.JDK_ONLY, TestJdkKind.FULL_JDK) @@ -337,7 +346,7 @@ open class TestKotlinScriptDummyDependenciesResolver : DependenciesResolver { ?: emptyList() } -class TestKotlinScriptDependenciesResolver : TestKotlinScriptDummyDependenciesResolver() { +open class TestKotlinScriptDependenciesResolver : TestKotlinScriptDummyDependenciesResolver() { private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() } @@ -369,6 +378,24 @@ class TestKotlinScriptDependenciesResolver : TestKotlinScriptDummyDependenciesRe class TestParamClass(@Suppress("unused") val memberNum: Int) +class ErrorReportingResolver : TestKotlinScriptDependenciesResolver() { + override fun resolve( + scriptContents: ScriptContents, + environment: Environment + ): ResolveResult { + return ResolveResult.Success( + super.resolve(scriptContents, environment).dependencies!!, + listOf( + ScriptReport("error", ScriptReport.Severity.ERROR, null), + ScriptReport("warning", ScriptReport.Severity.WARNING, ScriptReport.Position(1, 0)), + ScriptReport("info", ScriptReport.Severity.INFO, ScriptReport.Position(2, 0)), + ScriptReport("debug", ScriptReport.Severity.DEBUG, ScriptReport.Position(3, 0)) + + ) + ) + } +} + @ScriptTemplateDefinition( scriptFilePattern =".*\\.kts", resolver = TestKotlinScriptDummyDependenciesResolver::class) @@ -420,6 +447,9 @@ abstract class ScriptWithNullableProjection(val param: Array) @ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) abstract class ScriptWithArray2DParam(val param: Array>) +@ScriptTemplateDefinition(resolver = ErrorReportingResolver::class) +abstract class ScriptReportingErrors(val num: Int) + @Target(AnnotationTarget.FILE) @Retention(AnnotationRetention.RUNTIME) annotation class DependsOn(val path: String) diff --git a/idea/idea-analysis/idea-analysis.iml b/idea/idea-analysis/idea-analysis.iml index ea3b3ef65a4..16d7076c8fd 100644 --- a/idea/idea-analysis/idea-analysis.iml +++ b/idea/idea-analysis/idea-analysis.iml @@ -38,6 +38,5 @@ - \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt new file mode 100644 index 00000000000..7ee6aa21526 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeHighlighting.Pass +import com.intellij.codeHighlighting.TextEditorHighlightingPass +import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory +import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar +import com.intellij.codeInsight.daemon.impl.HighlightInfo +import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.lang.annotation.HighlightSeverity.* +import com.intellij.openapi.components.AbstractProjectComponent +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink +import org.jetbrains.kotlin.psi.KtFile +import kotlin.script.dependencies.ScriptReport + +class ScriptExternalHighlightingPass( + private val file: KtFile, + document: Document +) : TextEditorHighlightingPass(file.project, document), DumbAware { + override fun doCollectInformation(progress: ProgressIndicator) = Unit + + override fun doApplyInformationToEditor() { + val document = document ?: return + + val reports = file.virtualFile.getUserData(IdeScriptReportSink.Reports) ?: return + + val annotations = reports.mapNotNull { (message, severity, position) -> + val (startOffset, endOffset) = computeOffsets(document, position) ?: return@mapNotNull null + Annotation( + startOffset, + endOffset, + severity.convertSeverity() ?: return@mapNotNull null, + message, + message + ) + } + + val infos = annotations.map { HighlightInfo.fromAnnotation(it) } + UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) + } + + private fun computeOffsets(document: Document, position: ScriptReport.Position?): Pair? { + if (position == null) { + // TODO: better presentation of those errors + // if no position was specified, mark first two lines as an error + return computeOffsets(document, ScriptReport.Position(0, 0, 1)) + } + + val startLine = position.startLine.coerceLineIn(document) + val startOffset = document.offsetBy(startLine, position.startColumn) + + val endLine = position.endLine?.coerceAtLeast(startLine)?.coerceLineIn(document) ?: startLine + val endOffset = document.offsetBy( + endLine, + position.endColumn ?: document.getLineEndOffset(endLine) + ).coerceAtLeast(startOffset) + + // TODO: presentation when range is empty? + return startOffset to endOffset + } + + private fun Int.coerceLineIn(document: Document) = coerceIn(0, document.lineCount - 1) + + private fun Document.offsetBy(line: Int, col: Int): Int { + val offset = (getLineStartOffset(line) + col). + coerceIn(getLineStartOffset(line), getLineEndOffset(line)) + return offset + } + + private fun ScriptReport.Severity.convertSeverity(): HighlightSeverity? { + return when (this) { + ScriptReport.Severity.ERROR -> ERROR + ScriptReport.Severity.WARNING -> WARNING + ScriptReport.Severity.INFO -> INFORMATION + else -> null + } + } + + class Factory(project: Project, registrar: TextEditorHighlightingPassRegistrar) + : AbstractProjectComponent(project), TextEditorHighlightingPassFactory { + init { + registrar.registerTextEditorHighlightingPass(this, TextEditorHighlightingPassRegistrar.Anchor.BEFORE, Pass.UPDATE_FOLDING, false, false) + } + + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return ScriptExternalHighlightingPass(file, editor.document) + } + } +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/IdeScriptReportSink.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/IdeScriptReportSink.kt new file mode 100644 index 00000000000..0596b705d01 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/IdeScriptReportSink.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.core.script + +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.script.ScriptReportSink +import kotlin.script.dependencies.ScriptReport + +class IdeScriptReportSink : ScriptReportSink { + override fun attachReports(scriptFile: VirtualFile, reports: List) { + // TODO: persist errors between launches? + scriptFile.putUserData(Reports, reports) + } + + object Reports : Key>("KOTLIN_SCRIPT_REPORTS") +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/KotlinScriptConfigurationManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/KotlinScriptConfigurationManager.kt index 4666220ec71..9ff34494b2d 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/KotlinScriptConfigurationManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/KotlinScriptConfigurationManager.kt @@ -238,6 +238,7 @@ class KotlinScriptConfigurationManager( cacheLock.read { val lastTimeStamp = cache[path]?.requestInProgress?.timeStamp if (lastTimeStamp == currentTimeStamp) { + ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) if (cacheSync(result.dependencies ?: ScriptDependencies.Empty, oldDataAndRequest?.dependencies, path, file)) { invalidateLocalCaches() notifyRootsChanged() diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 72a2c42e27b..fb66d09c80b 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -38,6 +38,9 @@ org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory + + org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Factory + org.jetbrains.kotlin.idea.completion.LookupCancelWatcher @@ -272,6 +275,9 @@ + + diff --git a/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/script.kts b/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/script.kts new file mode 100644 index 00000000000..1800ab1c99f --- /dev/null +++ b/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/script.kts @@ -0,0 +1,4 @@ +val java = "j" +val scala = "s" + +val result = java + scala \ No newline at end of file diff --git a/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/template/template.kt b/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/template/template.kt new file mode 100644 index 00000000000..9d0766865d7 --- /dev/null +++ b/idea/testData/script/definition/highlighting/doNotSpeakAboutJava/template/template.kt @@ -0,0 +1,49 @@ +package custom.scriptDefinition + +import kotlin.script.dependencies.* +import kotlin.script.templates.* +import java.io.File + +class TestDependenciesResolver : DependenciesResolver { + override fun resolve(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult { + val reports = ArrayList() + scriptContents.text?.let { text -> + text.lines().forEachIndexed { lineIndex, line -> + val adjustedLine = line.replace(Regex("()|()|()|()"), "") + Regex("java").findAll(adjustedLine).forEach { + reports.add( + ScriptReport( + "Can't use", + ScriptReport.Severity.ERROR, + ScriptReport.Position(lineIndex, it.range.first, lineIndex, it.range.last + 1) + ) + ) + } + Regex("scala").findAll(adjustedLine).forEach { + reports.add( + ScriptReport( + "Shouldn't use", + ScriptReport.Severity.WARNING, + ScriptReport.Position(lineIndex, it.range.first, lineIndex, it.range.last + 1) + ) + ) + } + } + } + + return DependenciesResolver.ResolveResult.Success( + ScriptDependencies( + classpath = listOf(environment["template-classes"] as File) + ), + reports + ) + } +} + +@ScriptTemplateDefinition(TestDependenciesResolver::class, scriptFilePattern = "script.kts") +class Template : Base() + +open class Base { + val i = 3 + val str = "" +} \ No newline at end of file diff --git a/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/script.kts b/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/script.kts new file mode 100644 index 00000000000..e6d553e8811 --- /dev/null +++ b/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/script.kts @@ -0,0 +1,5 @@ +val java = "j" +val scala = "s" + +val result = java + +scala \ No newline at end of file diff --git a/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/template/template.kt b/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/template/template.kt new file mode 100644 index 00000000000..7c3fdace6d0 --- /dev/null +++ b/idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/template/template.kt @@ -0,0 +1,44 @@ +package custom.scriptDefinition + +import kotlin.script.dependencies.* +import kotlin.script.templates.* +import java.io.File +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Future + +class TestDependenciesResolver : ScriptDependenciesResolver { + override fun resolve( + script: ScriptContents, + environment: Map?, + report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit, previousDependencies: KotlinScriptExternalDependencies? + ): Future { + script.text?.let { text -> + text.lines().forEachIndexed { lineIndex, line -> + val adjustedLine = line.replace(Regex("()|()|()|()"), "") + Regex("java").findAll(adjustedLine).forEach { + val columnIndex = it.range.first + report(ScriptDependenciesResolver.ReportSeverity.ERROR, "Can't use", ScriptContents.Position(lineIndex, columnIndex)) + } + Regex("scala").findAll(adjustedLine).forEach { + val columnIndex = it.range.first + report(ScriptDependenciesResolver.ReportSeverity.WARNING, "Shouldn't use", ScriptContents.Position(lineIndex, columnIndex)) + } + } + } + + + return CompletableFuture.completedFuture( + object : KotlinScriptExternalDependencies { + override val classpath: Iterable = listOf(environment?.get("template-classes") as File) + }) + + } +} + +@ScriptTemplateDefinition(TestDependenciesResolver::class, scriptFilePattern = "script.kts") +class Template : Base() + +open class Base { + val i = 3 + val str = "" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java index a1bc58a6b35..baa5040b6f3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java @@ -54,6 +54,18 @@ public class ScriptConfigurationHighlightingTestGenerated extends AbstractScript doTest(fileName); } + @TestMetadata("doNotSpeakAboutJava") + public void testDoNotSpeakAboutJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/doNotSpeakAboutJava/"); + doTest(fileName); + } + + @TestMetadata("doNotSpeakAboutJavaLegacy") + public void testDoNotSpeakAboutJavaLegacy() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/doNotSpeakAboutJavaLegacy/"); + doTest(fileName); + } + @TestMetadata("simple") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/simple/");