Filter diagnostics in the CLI compiler, as well as in the IDE

This commit is contained in:
Andrey Breslav
2014-06-17 17:40:45 +04:00
parent 61c7c2f1a1
commit 9ecbeeb100
4 changed files with 66 additions and 44 deletions
@@ -30,6 +30,7 @@ import kotlin.modules.Module;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.asJava.FilteredJvmDiagnostics;
import org.jetbrains.jet.cli.common.CLIConfigurationKeys; import org.jetbrains.jet.cli.common.CLIConfigurationKeys;
import org.jetbrains.jet.cli.common.CompilerPlugin; import org.jetbrains.jet.cli.common.CompilerPlugin;
import org.jetbrains.jet.cli.common.CompilerPluginContext; import org.jetbrains.jet.cli.common.CompilerPluginContext;
@@ -346,7 +347,10 @@ public class KotlinToJVMBytecodeCompiler {
); );
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION); KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION);
AnalyzerWithCompilerReport.reportDiagnostics( AnalyzerWithCompilerReport.reportDiagnostics(
diagnosticHolder.getBindingContext().getDiagnostics(), new FilteredJvmDiagnostics(
diagnosticHolder.getBindingContext().getDiagnostics(),
exhaust.getBindingContext().getDiagnostics()
),
environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
); );
return generationState; return generationState;
@@ -66,53 +66,63 @@ public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Dia
val result = doGetDiagnostics() val result = doGetDiagnostics()
if (result == null) return null if (result == null) return null
return object : Diagnostics by result { return FilteredJvmDiagnostics(result, otherDiagnostics)
}
private fun alreadyReported(psiElement: PsiElement): Boolean { class FilteredJvmDiagnostics(val jvmDiagnostics: Diagnostics, val otherDiagnostics: Diagnostics) : Diagnostics by jvmDiagnostics {
return otherDiagnostics.forElement(psiElement).any { it.getFactory() in setOf(CONFLICTING_OVERLOADS, REDECLARATION) }
|| psiElement is JetPropertyAccessor && alreadyReported(psiElement.getParent()!!) private fun alreadyReported(psiElement: PsiElement): Boolean {
return otherDiagnostics.forElement(psiElement).any { it.getFactory() in setOf(CONFLICTING_OVERLOADS, REDECLARATION) }
|| psiElement is JetPropertyAccessor && alreadyReported(psiElement.getParent()!!)
}
override fun forElement(psiElement: PsiElement): Collection<Diagnostic> {
val jvmDiagnosticFactories = setOf(CONFLICTING_JVM_DECLARATIONS, ACCIDENTAL_OVERRIDE)
fun Diagnostic.data() = cast(this, jvmDiagnosticFactories).getA()
val (conflicting, other) = jvmDiagnostics.forElement(psiElement).partition { it.getFactory() in jvmDiagnosticFactories }
if (alreadyReported(psiElement)) {
// CONFLICTING_OVERLOADS already reported, no need to duplicate it
return other
} }
override fun forElement(psiElement: PsiElement): Collection<Diagnostic> { val filtered = arrayListOf<Diagnostic>()
val jvmDiagnosticFactories = setOf(CONFLICTING_JVM_DECLARATIONS, ACCIDENTAL_OVERRIDE) conflicting.groupBy {
fun Diagnostic.data() = cast(this, jvmDiagnosticFactories).getA() it.data().signature.name
val (conflicting, other) = result.forElement(element).partition { it.getFactory() in jvmDiagnosticFactories } }.forEach {
if (alreadyReported(psiElement)) { val diagnostics = it.getValue()
// CONFLICTING_OVERLOADS already reported, no need to duplicate it if (diagnostics.size <= 1) {
return other filtered.addAll(diagnostics)
} }
else {
val filtered = arrayListOf<Diagnostic>() filtered.addAll(
conflicting.groupBy { diagnostics.filter {
it.data().signature.name me ->
}.forEach { diagnostics.none {
val diagnostics = it.getValue() other ->
if (diagnostics.size <= 1) { me != other && (
filtered.addAll(diagnostics) // in case of implementation copied from a super trait there will be both diagnostics on the same signature
} me.getFactory() == ACCIDENTAL_OVERRIDE && other.getFactory() == CONFLICTING_JVM_DECLARATIONS
else { // there are paris of corresponding signatures that frequently clash simultaneously: package facade & part, trait and trait-impl
filtered.addAll( || other.data() higherThan me.data()
diagnostics.filter { )
me ->
diagnostics.none {
other ->
me != other && (
// in case of implementation copied from a super trait there will be both diagnostics on the same signature
me.getFactory() == ACCIDENTAL_OVERRIDE && other.getFactory() == CONFLICTING_JVM_DECLARATIONS
// there are paris of corresponding signatures that frequently clash simultaneously: package facade & part, trait and trait-impl
|| other.data() higherThan me.data()
)
}
} }
) }
} )
} }
return filtered + other
} }
return filtered + other
}
override fun all(): Collection<Diagnostic> {
return jvmDiagnostics.all()
.map { it.getPsiElement() }
.toSet()
.flatMap { forElement(it) }
} }
} }
private fun ConflictingJvmDeclarationsData.higherThan(other: ConflictingJvmDeclarationsData): Boolean { private fun ConflictingJvmDeclarationsData.higherThan(other: ConflictingJvmDeclarationsData): Boolean {
return when (other.classOrigin.originKind) { return when (other.classOrigin.originKind) {
PACKAGE_PART -> this.classOrigin.originKind == PACKAGE_FACADE PACKAGE_PART -> this.classOrigin.originKind == PACKAGE_FACADE
@@ -11,3 +11,11 @@ class A : B() {
fun getB(): Int = 1 fun getB(): Int = 1
val b: Int = 1 val b: Int = 1
trait Tr {
fun getTr() = 1
}
class SubTr : Tr {
val tr = 1
}
+6 -6
View File
@@ -7,16 +7,16 @@ ERROR: $TESTDATA_DIR$/signatureClash.kt: (8, 5) Platform declaration clash: The
ERROR: $TESTDATA_DIR$/signatureClash.kt: (9, 5) Platform declaration clash: The following declarations have the same JVM signature (getA()I): ERROR: $TESTDATA_DIR$/signatureClash.kt: (9, 5) Platform declaration clash: The following declarations have the same JVM signature (getA()I):
fun getA(): kotlin.Int fun getA(): kotlin.Int
fun <get-a>(): kotlin.Int fun <get-a>(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (12, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I):
fun getB(): kotlin.Int
fun <get-b>(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (12, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I): ERROR: $TESTDATA_DIR$/signatureClash.kt: (12, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I):
fun <get-b>(): kotlin.Int fun <get-b>(): kotlin.Int
fun getB(): kotlin.Int fun getB(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (13, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I):
fun getB(): kotlin.Int
fun <get-b>(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (13, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I): ERROR: $TESTDATA_DIR$/signatureClash.kt: (13, 1) Platform declaration clash: The following declarations have the same JVM signature (getB()I):
fun <get-b>(): kotlin.Int fun <get-b>(): kotlin.Int
fun getB(): kotlin.Int fun getB(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (16, 5) Platform declaration clash: The following declarations have the same JVM signature (getTr()I):
fun <get-tr>(): kotlin.Int
fun getTr(): kotlin.Int
ERROR: $TESTDATA_DIR$/signatureClash.kt: (20, 5) Platform declaration clash: The following declarations have the same JVM signature (getTr()I):
fun <get-tr>(): kotlin.Int
fun getTr(): kotlin.Int
COMPILATION_ERROR COMPILATION_ERROR