Support -Werror CLI argument to treat warnings as errors
The option is named "warningsAsErrors" in the Gradle plugin #KT-10563 Fixed
This commit is contained in:
committed by
Ilya Gorbunov
parent
897261a8a6
commit
5cbcbe4a9c
+2
-1
@@ -74,7 +74,8 @@ class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(depe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createMessageCollector() = object : GroupingMessageCollector(
|
private fun createMessageCollector() = object : GroupingMessageCollector(
|
||||||
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, /* verbose = */ false)
|
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, false),
|
||||||
|
false
|
||||||
) {
|
) {
|
||||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
|
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
|
||||||
// Only report diagnostics without a particular location because there's plenty of errors in built-in sources
|
// Only report diagnostics without a particular location because there's plenty of errors in built-in sources
|
||||||
|
|||||||
+4
@@ -44,4 +44,8 @@ abstract class CommonToolArguments : Freezable(), Serializable {
|
|||||||
@GradleOption(DefaultValues.BooleanFalseDefault::class)
|
@GradleOption(DefaultValues.BooleanFalseDefault::class)
|
||||||
@Argument(value = "-nowarn", description = "Generate no warnings")
|
@Argument(value = "-nowarn", description = "Generate no warnings")
|
||||||
var suppressWarnings: Boolean by FreezableVar(false)
|
var suppressWarnings: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
|
@GradleOption(DefaultValues.BooleanFalseDefault::class)
|
||||||
|
@Argument(value = "-Werror", description = "Report an error if there are any warnings")
|
||||||
|
var warningsAsErrors: Boolean by FreezableVar(false)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -35,11 +35,14 @@ public enum CompilerMessageSeverity {
|
|||||||
*/
|
*/
|
||||||
OUTPUT;
|
OUTPUT;
|
||||||
|
|
||||||
public static final EnumSet<CompilerMessageSeverity> ERRORS = EnumSet.of(ERROR, EXCEPTION);
|
|
||||||
public static final EnumSet<CompilerMessageSeverity> VERBOSE = EnumSet.of(LOGGING);
|
public static final EnumSet<CompilerMessageSeverity> VERBOSE = EnumSet.of(LOGGING);
|
||||||
|
|
||||||
public boolean isError() {
|
public boolean isError() {
|
||||||
return ERRORS.contains(this);
|
return this == EXCEPTION || this == ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWarning() {
|
||||||
|
return this == STRONG_WARNING || this == WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+18
-3
@@ -24,16 +24,19 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class GroupingMessageCollector implements MessageCollector {
|
public class GroupingMessageCollector implements MessageCollector {
|
||||||
private final MessageCollector delegate;
|
private final MessageCollector delegate;
|
||||||
|
private final boolean treatWarningsAsErrors;
|
||||||
|
|
||||||
// Note that the key in this map can be null
|
// Note that the key in this map can be null
|
||||||
private final Multimap<CompilerMessageLocation, Message> groupedMessages = LinkedHashMultimap.create();
|
private final Multimap<CompilerMessageLocation, Message> groupedMessages = LinkedHashMultimap.create();
|
||||||
|
|
||||||
public GroupingMessageCollector(@NotNull MessageCollector delegate) {
|
public GroupingMessageCollector(@NotNull MessageCollector delegate, boolean treatWarningsAsErrors) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
this.treatWarningsAsErrors = treatWarningsAsErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,17 +60,29 @@ public class GroupingMessageCollector implements MessageCollector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasErrors() {
|
public boolean hasErrors() {
|
||||||
|
return hasExplicitErrors() || (treatWarningsAsErrors && hasWarnings());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasExplicitErrors() {
|
||||||
return groupedMessages.entries().stream().anyMatch(entry -> entry.getValue().severity.isError());
|
return groupedMessages.entries().stream().anyMatch(entry -> entry.getValue().severity.isError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasWarnings() {
|
||||||
|
return groupedMessages.entries().stream().anyMatch(entry -> entry.getValue().severity.isWarning());
|
||||||
|
}
|
||||||
|
|
||||||
public void flush() {
|
public void flush() {
|
||||||
boolean hasErrors = hasErrors();
|
boolean hasExplicitErrors = hasExplicitErrors();
|
||||||
|
|
||||||
|
if (treatWarningsAsErrors && !hasExplicitErrors && hasWarnings()) {
|
||||||
|
report(CompilerMessageSeverity.ERROR, "warnings found and -Werror specified", null);
|
||||||
|
}
|
||||||
|
|
||||||
List<CompilerMessageLocation> sortedKeys =
|
List<CompilerMessageLocation> sortedKeys =
|
||||||
CollectionsKt.sortedWith(groupedMessages.keySet(), Comparator.nullsFirst(CompilerMessageLocationComparator.INSTANCE));
|
CollectionsKt.sortedWith(groupedMessages.keySet(), Comparator.nullsFirst(CompilerMessageLocationComparator.INSTANCE));
|
||||||
for (CompilerMessageLocation location : sortedKeys) {
|
for (CompilerMessageLocation location : sortedKeys) {
|
||||||
for (Message message : groupedMessages.get(location)) {
|
for (Message message : groupedMessages.get(location)) {
|
||||||
if (!hasErrors || message.severity.isError() || message.severity == CompilerMessageSeverity.STRONG_WARNING) {
|
if (!hasExplicitErrors || message.severity.isError() || message.severity == CompilerMessageSeverity.STRONG_WARNING) {
|
||||||
delegate.report(message.severity, message.message, message.location);
|
delegate.report(message.severity, message.message, message.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public ExitCode execImpl(@NotNull MessageCollector messageCollector, @NotNull Services services, @NotNull A arguments) {
|
public ExitCode execImpl(@NotNull MessageCollector messageCollector, @NotNull Services services, @NotNull A arguments) {
|
||||||
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector);
|
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector, arguments.getWarningsAsErrors());
|
||||||
|
|
||||||
CompilerConfiguration configuration = new CompilerConfiguration();
|
CompilerConfiguration configuration = new CompilerConfiguration();
|
||||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, groupingCollector);
|
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, groupingCollector);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ abstract class CLITool<A : CommonToolArguments> {
|
|||||||
fun exec(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode {
|
fun exec(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode {
|
||||||
printVersionIfNeeded(messageCollector, arguments)
|
printVersionIfNeeded(messageCollector, arguments)
|
||||||
|
|
||||||
val fixedMessageCollector = if (arguments.suppressWarnings) {
|
val fixedMessageCollector = if (arguments.suppressWarnings && !arguments.warningsAsErrors) {
|
||||||
FilteringMessageCollector(messageCollector, Predicate.isEqual(CompilerMessageSeverity.WARNING))
|
FilteringMessageCollector(messageCollector, Predicate.isEqual(CompilerMessageSeverity.WARNING))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+2
-1
@@ -28,7 +28,8 @@ class ReplTerminalDiagnosticMessageHolder : MessageCollectorBasedReporter, Diagn
|
|||||||
private val outputStream = ByteArrayOutputStream()
|
private val outputStream = ByteArrayOutputStream()
|
||||||
|
|
||||||
override val messageCollector: GroupingMessageCollector = GroupingMessageCollector(
|
override val messageCollector: GroupingMessageCollector = GroupingMessageCollector(
|
||||||
PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false)
|
PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false),
|
||||||
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
override val renderedDiagnostics: String
|
override val renderedDiagnostics: String
|
||||||
|
|||||||
+1
@@ -8,4 +8,5 @@ where possible options include:
|
|||||||
-nowarn Generate no warnings
|
-nowarn Generate no warnings
|
||||||
-verbose Enable verbose logging output
|
-verbose Enable verbose logging output
|
||||||
-version Display compiler version
|
-version Display compiler version
|
||||||
|
-Werror Report an error if there are any warnings
|
||||||
OK
|
OK
|
||||||
|
|||||||
Vendored
+1
@@ -25,4 +25,5 @@ where possible options include:
|
|||||||
-nowarn Generate no warnings
|
-nowarn Generate no warnings
|
||||||
-verbose Enable verbose logging output
|
-verbose Enable verbose logging output
|
||||||
-version Display compiler version
|
-version Display compiler version
|
||||||
|
-Werror Report an error if there are any warnings
|
||||||
OK
|
OK
|
||||||
|
|||||||
Vendored
+1
@@ -23,4 +23,5 @@ where possible options include:
|
|||||||
-nowarn Generate no warnings
|
-nowarn Generate no warnings
|
||||||
-verbose Enable verbose logging output
|
-verbose Enable verbose logging output
|
||||||
-version Display compiler version
|
-version Display compiler version
|
||||||
|
-Werror Report an error if there are any warnings
|
||||||
OK
|
OK
|
||||||
|
|||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
$TESTDATA_DIR$/werror.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Werror
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(s: String, t: String?) {
|
||||||
|
s!!
|
||||||
|
t?.toString()
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
error: warnings found and -Werror specified
|
||||||
|
compiler/testData/cli/jvm/werror.kt:2:6: warning: unnecessary non-null assertion (!!) on a non-null receiver of type String
|
||||||
|
s!!
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
$TESTDATA_DIR$/werrorWithExplicitError.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Werror
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(s: String, t: String?) {
|
||||||
|
s!!
|
||||||
|
t?.toString()
|
||||||
|
t.length
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
compiler/testData/cli/jvm/werrorWithExplicitError.kt:4:6: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
|
||||||
|
t.length
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
$TESTDATA_DIR$/werrorWithNoWarn.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Werror
|
||||||
|
-nowarn
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(s: String, t: String?) {
|
||||||
|
s!!
|
||||||
|
t?.toString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
error: warnings found and -Werror specified
|
||||||
|
compiler/testData/cli/jvm/werrorWithNoWarn.kt:2:6: warning: unnecessary non-null assertion (!!) on a non-null receiver of type String
|
||||||
|
s!!
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
$TESTDATA_DIR$/werrorWithStrongWarning.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Werror
|
||||||
|
-cp
|
||||||
|
non-existing-path.jar
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(s: String, t: String?) {
|
||||||
|
s!!
|
||||||
|
t?.toString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
warning: classpath entry points to a non-existent location: non-existing-path.jar
|
||||||
|
error: warnings found and -Werror specified
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -476,6 +476,30 @@ public class CliTestGenerated extends AbstractCliTest {
|
|||||||
doJvmTest(fileName);
|
doJvmTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("werror.args")
|
||||||
|
public void testWerror() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/werror.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("werrorWithExplicitError.args")
|
||||||
|
public void testWerrorWithExplicitError() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/werrorWithExplicitError.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("werrorWithNoWarn.args")
|
||||||
|
public void testWerrorWithNoWarn() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/werrorWithNoWarn.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("werrorWithStrongWarning.args")
|
||||||
|
public void testWerrorWithStrongWarning() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/werrorWithStrongWarning.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("wrongAbiVersion.args")
|
@TestMetadata("wrongAbiVersion.args")
|
||||||
public void testWrongAbiVersion() throws Exception {
|
public void testWrongAbiVersion() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/wrongAbiVersion.args");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/wrongAbiVersion.args");
|
||||||
|
|||||||
+6
@@ -17,4 +17,10 @@ interface KotlinCommonOptions : org.jetbrains.kotlin.gradle.dsl.KotlinCommonToo
|
|||||||
* Default value: null
|
* Default value: null
|
||||||
*/
|
*/
|
||||||
var languageVersion: kotlin.String?
|
var languageVersion: kotlin.String?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report an error if there are any warnings
|
||||||
|
* Default value: false
|
||||||
|
*/
|
||||||
|
var warningsAsErrors: kotlin.Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -24,6 +24,11 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko
|
|||||||
get() = languageVersionField ?: null
|
get() = languageVersionField ?: null
|
||||||
set(value) { languageVersionField = value }
|
set(value) { languageVersionField = value }
|
||||||
|
|
||||||
|
private var warningsAsErrorsField: kotlin.Boolean? = null
|
||||||
|
override var warningsAsErrors: kotlin.Boolean
|
||||||
|
get() = warningsAsErrorsField ?: false
|
||||||
|
set(value) { warningsAsErrorsField = value }
|
||||||
|
|
||||||
private var friendModulesDisabledField: kotlin.Boolean? = null
|
private var friendModulesDisabledField: kotlin.Boolean? = null
|
||||||
override var friendModulesDisabled: kotlin.Boolean
|
override var friendModulesDisabled: kotlin.Boolean
|
||||||
get() = friendModulesDisabledField ?: false
|
get() = friendModulesDisabledField ?: false
|
||||||
@@ -84,6 +89,7 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko
|
|||||||
verboseField?.let { args.verbose = it }
|
verboseField?.let { args.verbose = it }
|
||||||
apiVersionField?.let { args.apiVersion = it }
|
apiVersionField?.let { args.apiVersion = it }
|
||||||
languageVersionField?.let { args.languageVersion = it }
|
languageVersionField?.let { args.languageVersion = it }
|
||||||
|
warningsAsErrorsField?.let { args.warningsAsErrors = it }
|
||||||
friendModulesDisabledField?.let { args.friendModulesDisabled = it }
|
friendModulesDisabledField?.let { args.friendModulesDisabled = it }
|
||||||
mainField?.let { args.main = it }
|
mainField?.let { args.main = it }
|
||||||
metaInfoField?.let { args.metaInfo = it }
|
metaInfoField?.let { args.metaInfo = it }
|
||||||
@@ -103,6 +109,7 @@ internal fun org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments.fil
|
|||||||
verbose = false
|
verbose = false
|
||||||
apiVersion = null
|
apiVersion = null
|
||||||
languageVersion = null
|
languageVersion = null
|
||||||
|
warningsAsErrors = false
|
||||||
friendModulesDisabled = false
|
friendModulesDisabled = false
|
||||||
main = "call"
|
main = "call"
|
||||||
metaInfo = true
|
metaInfo = true
|
||||||
|
|||||||
+7
@@ -24,6 +24,11 @@ internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.K
|
|||||||
get() = languageVersionField ?: null
|
get() = languageVersionField ?: null
|
||||||
set(value) { languageVersionField = value }
|
set(value) { languageVersionField = value }
|
||||||
|
|
||||||
|
private var warningsAsErrorsField: kotlin.Boolean? = null
|
||||||
|
override var warningsAsErrors: kotlin.Boolean
|
||||||
|
get() = warningsAsErrorsField ?: false
|
||||||
|
set(value) { warningsAsErrorsField = value }
|
||||||
|
|
||||||
private var includeRuntimeField: kotlin.Boolean? = null
|
private var includeRuntimeField: kotlin.Boolean? = null
|
||||||
override var includeRuntime: kotlin.Boolean
|
override var includeRuntime: kotlin.Boolean
|
||||||
get() = includeRuntimeField ?: false
|
get() = includeRuntimeField ?: false
|
||||||
@@ -64,6 +69,7 @@ internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.K
|
|||||||
verboseField?.let { args.verbose = it }
|
verboseField?.let { args.verbose = it }
|
||||||
apiVersionField?.let { args.apiVersion = it }
|
apiVersionField?.let { args.apiVersion = it }
|
||||||
languageVersionField?.let { args.languageVersion = it }
|
languageVersionField?.let { args.languageVersion = it }
|
||||||
|
warningsAsErrorsField?.let { args.warningsAsErrors = it }
|
||||||
includeRuntimeField?.let { args.includeRuntime = it }
|
includeRuntimeField?.let { args.includeRuntime = it }
|
||||||
javaParametersField?.let { args.javaParameters = it }
|
javaParametersField?.let { args.javaParameters = it }
|
||||||
jdkHomeField?.let { args.jdkHome = it }
|
jdkHomeField?.let { args.jdkHome = it }
|
||||||
@@ -79,6 +85,7 @@ internal fun org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments.fi
|
|||||||
verbose = false
|
verbose = false
|
||||||
apiVersion = null
|
apiVersion = null
|
||||||
languageVersion = null
|
languageVersion = null
|
||||||
|
warningsAsErrors = false
|
||||||
includeRuntime = false
|
includeRuntime = false
|
||||||
javaParameters = false
|
javaParameters = false
|
||||||
jdkHome = null
|
jdkHome = null
|
||||||
|
|||||||
Reference in New Issue
Block a user