Propagate reports from script dependency resolver
Compiler: show as compiler messages IDE: annotate code in a separate highlighting pass
This commit is contained in:
@@ -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<ScriptReport>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ScriptReport>)
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<out Any>,
|
||||
environment: Map<String, Any?>? = 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<String?>)
|
||||
@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class)
|
||||
abstract class ScriptWithArray2DParam(val param: Array<Array<in String>>)
|
||||
|
||||
@ScriptTemplateDefinition(resolver = ErrorReportingResolver::class)
|
||||
abstract class ScriptReportingErrors(val num: Int)
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class DependsOn(val path: String)
|
||||
|
||||
Reference in New Issue
Block a user