Skip to content

Commit

Permalink
Less noisy output for detekt with Type solving (#4423)
Browse files Browse the repository at this point in the history
* Make detekt less noisy
  • Loading branch information
BraisGabin committed Jan 5, 2022
1 parent 20891d4 commit 4b7107a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 24 deletions.
Expand Up @@ -3,29 +3,36 @@ package io.gitlab.arturbosch.detekt.core
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.PlainTextMessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import java.io.PrintStream

internal fun generateBindingContext(
environment: KotlinCoreEnvironment,
classpath: List<String>,
files: List<KtFile>,
debugPrinter: (() -> String) -> Unit,
warningPrinter: (String) -> Unit,
): BindingContext {
if (classpath.isEmpty()) {
return BindingContext.EMPTY
}

val messageCollector = DetektMessageCollector(
minSeverity = CompilerMessageSeverity.ERROR,
debugPrinter = debugPrinter,
warningPrinter = warningPrinter,
)

val analyzer = AnalyzerWithCompilerReport(
DetektMessageCollector(minSeverity = CompilerMessageSeverity.ERROR),
environment.configuration.languageVersionSettings
messageCollector,
environment.configuration.languageVersionSettings,
)
analyzer.analyzeAndReport(files) {
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
Expand All @@ -37,17 +44,32 @@ internal fun generateBindingContext(
::FileBasedDeclarationProviderFactory
)
}

messageCollector.printIssuesCountIfAny()

return analyzer.analysisResult.bindingContext
}

internal class DetektMessageCollector(
errorStream: PrintStream = System.err,
verbose: Boolean = false,
private val minSeverity: CompilerMessageSeverity = CompilerMessageSeverity.ERROR
) : PrintingMessageCollector(errorStream, DetektMessageRenderer, verbose) {
private val minSeverity: CompilerMessageSeverity,
private val debugPrinter: (() -> String) -> Unit,
private val warningPrinter: (String) -> Unit,
) : MessageCollector by MessageCollector.NONE {
private var messages = 0

override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
if (severity.ordinal <= minSeverity.ordinal) {
super.report(severity, message, location)
debugPrinter { DetektMessageRenderer.render(severity, message, location) }
messages++
}
}

fun printIssuesCountIfAny() {
if (messages > 0) {
warningPrinter(
"The BindingContext was created with $messages issues. " +
"Run detekt with --debug to see the error messages."
)
}
}
}
Expand Down
Expand Up @@ -63,7 +63,7 @@ internal class DefaultLifecycle(
override val settings: ProcessingSettings,
override val parsingStrategy: ParsingStrategy,
override val bindingProvider: (files: List<KtFile>) -> BindingContext =
{ generateBindingContext(settings.environment, settings.classpath, it) },
{ generateBindingContext(settings.environment, settings.classpath, it, settings::debug, settings::info) },
override val processorsProvider: () -> List<FileProcessListener> =
{ FileProcessorLocator(settings).load() },
override val ruleSetsProvider: () -> List<RuleSetProvider> =
Expand Down
@@ -1,44 +1,88 @@
package io.gitlab.arturbosch.detekt.core

import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.slot
import io.mockk.verify
import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.spekframework.spek2.Spek
import org.spekframework.spek2.lifecycle.CachingMode
import org.spekframework.spek2.style.specification.describe
import java.io.PrintStream

internal object DetektMessageCollectorSpec : Spek({
describe("DetektMessageCollector") {
val errorStream by memoized { CollectingPrintStream() }
val subject by memoized {
val debugPrinter: (() -> String) -> Unit by memoized(CachingMode.TEST) {
mockk {
every { this@mockk.invoke(any()) } returns Unit
}
}
val warningPrinter: (String) -> Unit by memoized(CachingMode.TEST) {
mockk {
every { this@mockk.invoke(any()) } returns Unit
}
}
val subject by memoized(CachingMode.TEST) {
DetektMessageCollector(
errorStream = errorStream,
minSeverity = CompilerMessageSeverity.INFO
minSeverity = CompilerMessageSeverity.INFO,
debugPrinter = debugPrinter,
warningPrinter = warningPrinter,
)
}

describe("message with min severity") {
beforeEachTest { subject.report(CompilerMessageSeverity.INFO, "message", null) }

it("prints the message") {
assertThat(errorStream.messages).containsExactly("info: message")
val slot = slot<() -> String>()
verify { debugPrinter.invoke(capture(slot)) }
assertThat(slot.captured()).isEqualTo("info: message")
}

it("adds up to the message count") {
subject.printIssuesCountIfAny()

verify {
warningPrinter(
"The BindingContext was created with 1 issues. " +
"Run detekt with --debug to see the error messages."
)
}
}
}
describe("message with higher severity than the min severity") {
beforeEachTest { subject.report(CompilerMessageSeverity.WARNING, "message", null) }

it("prints the message") {
assertThat(errorStream.messages).containsExactly("warning: message")
val slot = slot<() -> String>()
verify { debugPrinter.invoke(capture(slot)) }
assertThat(slot.captured()).isEqualTo("warning: message")
}

it("adds up to the message count") {
subject.printIssuesCountIfAny()

verify {
warningPrinter(
"The BindingContext was created with 1 issues. " +
"Run detekt with --debug to see the error messages."
)
}
}
}
describe("message with lower severity than the min severity") {
beforeEachTest { subject.report(CompilerMessageSeverity.LOGGING, "message", null) }

it("ignores the message") {
assertThat(errorStream.messages).isEmpty()
verify { debugPrinter wasNot Called }
}

it("doesn't add up to the message count") {
subject.printIssuesCountIfAny()

verify { warningPrinter wasNot Called }
}
}
}
})

private class CollectingPrintStream(val messages: MutableList<String> = mutableListOf()) : PrintStream(System.err) {
override fun println(message: String) {
messages.add(message)
}
}

0 comments on commit 4b7107a

Please sign in to comment.