From c0cbd2e3edff5c89c9ab43d30353e57bc2c0cdab Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 17 Jun 2022 12:40:17 +0400 Subject: [PATCH] [Native][tests] Fail tests on unexpected non-syntax/semantic warnings --- .../support/compilation/CompilerCall.kt | 11 +- .../NativeTestGroupingMessageCollector.kt | 118 ++++++++++++++++++ 2 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/NativeTestGroupingMessageCollector.kt diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilerCall.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilerCall.kt index e5d5e8e1ea8..42ee9b7a624 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilerCall.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilerCall.kt @@ -6,10 +6,7 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.compilation import org.jetbrains.kotlin.cli.common.ExitCode -import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageRenderer -import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector +import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.compilerRunner.processCompilerOutput import org.jetbrains.kotlin.config.Services @@ -48,9 +45,9 @@ internal fun callCompiler(compilerArgs: Array, kotlinNativeClassLoader: ByteArrayOutputStream().use { outputStream -> PrintStream(outputStream).use { printStream -> - messageCollector = GroupingMessageCollector( - PrintingMessageCollector(printStream, MessageRenderer.SYSTEM_INDEPENDENT_RELATIVE_PATHS, true), - false + messageCollector = NativeTestGroupingMessageCollector( + compilerArgs = compilerArgs, + delegate = PrintingMessageCollector(printStream, MessageRenderer.SYSTEM_INDEPENDENT_RELATIVE_PATHS, /*verbose =*/ true), ) processCompilerOutput( messageCollector, diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/NativeTestGroupingMessageCollector.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/NativeTestGroupingMessageCollector.kt new file mode 100644 index 00000000000..22cb4046e77 --- /dev/null +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/NativeTestGroupingMessageCollector.kt @@ -0,0 +1,118 @@ +/* + * Copyright 2010-2022 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.konan.blackboxtest.support.compilation + +import com.intellij.openapi.util.text.StringUtil.substringAfter +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation +import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector +import org.jetbrains.kotlin.cli.common.messages.MessageCollector + +/** + * Special implementation of [GroupingMessageCollector] that raises the severity of unexpected + * compiler warnings to errors, this way failing the tests. + */ +internal class NativeTestGroupingMessageCollector( + compilerArgs: Array, + delegate: MessageCollector +) : GroupingMessageCollector( + delegate, + /*treatWarningsAsErrors =*/ false +) { + private var hasWarningsWithRaisedSeverity: Boolean = false + + private val languageFeaturesInCompilerArgs: Set by lazy { + compilerArgs.mapNotNullTo(hashSetOf(), ::parseLanguageFeatureArg) + } + + private val pathOfCachedLibraryWithTests: String? by lazy { + var isProducingStaticCache = false + var includedLibraryName: String? = null + var cachedLibraryName: String? = null + + for ((index, arg) in compilerArgs.withIndex()) { + if ((arg == "-p" || arg == "-produce") + && index < compilerArgs.size - 1 + && compilerArgs[index + 1] == "static_cache" + ) { + isProducingStaticCache = true + } else { + includedLibraryName = includedLibraryName ?: substringAfter(arg, "-Xinclude=") + cachedLibraryName = cachedLibraryName ?: substringAfter(arg, "-Xadd-cache=") + } + + if (isProducingStaticCache && includedLibraryName != null && cachedLibraryName != null) + return@lazy cachedLibraryName.takeIf { includedLibraryName == cachedLibraryName } + } + + null + } + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) = + super.report(adjustSeverity(severity, message, location), message, location) + + private fun adjustSeverity(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) = + when { + !severity.isWarning -> { + // Don't adjust severity for non-warnings. + severity + } + location != null -> { + // Don't adjust severity for any syntax and semantic warnings. + severity + } + isPreReleaseBinariesWarning(message) + || isUnsafeCompilerArgumentsWarning(message) + || isLibraryIncludedMoreThanOnceWarning(message) -> { + // These warnings are known and should not be reported as errors. + severity + } + else -> { + hasWarningsWithRaisedSeverity = true + CompilerMessageSeverity.ERROR + } + } + + private fun isPreReleaseBinariesWarning(message: String): Boolean { + val languageFeatures = substringAfter(message, PRE_RELEASE_WARNING_PREFIX) + ?.split(", ") + ?.takeIf(Collection::isNotEmpty) + ?: return false + + return languageFeaturesInCompilerArgs.containsAll(languageFeatures) + } + + private fun isUnsafeCompilerArgumentsWarning(message: String): Boolean { + val languageFeatures = substringAfter(message, UNSAFE_COMPILER_ARGS_WARNING_PREFIX) + ?.lineSequence() + ?.takeWhile(String::isNotBlank) + ?.map { parseLanguageFeatureArg(it) ?: "" } + ?.toList() + ?.takeIf(Collection::isNotEmpty) + ?: return false + + return languageFeaturesInCompilerArgs.containsAll(languageFeatures) + } + + private fun isLibraryIncludedMoreThanOnceWarning(message: String): Boolean { + val libraryPath = substringAfter(message, LIBRARY_INCLUDED_MORE_THAN_ONCE_WARNING_PREFIX) + ?.takeIf(String::isNotBlank) + ?: return false + + return libraryPath == pathOfCachedLibraryWithTests + } + + override fun hasErrors() = hasWarningsWithRaisedSeverity || super.hasErrors() + + companion object { + private const val PRE_RELEASE_WARNING_PREFIX = "Following manually enabled features will force generation of pre-release binaries: " + private const val UNSAFE_COMPILER_ARGS_WARNING_PREFIX = "ATTENTION!\nThis build uses unsafe internal compiler arguments:\n\n" + private const val LIBRARY_INCLUDED_MORE_THAN_ONCE_WARNING_PREFIX = "library included more than once: " + + private fun parseLanguageFeatureArg(arg: String): String? = + substringAfter(arg, "-XXLanguage:-") ?: substringAfter(arg, "-XXLanguage:+") + } +}