Hello, I am writing a compiler plugin to modify er...
# compiler
a
Hello, I am writing a compiler plugin to modify errors and warnings found by the compiler. I have a code like this, that can read the diagnostics
Copy code
class WarnningsExtension(
) : AnalysisHandlerExtension {

    override fun analysisCompleted(project: Project, module: ModuleDescriptor, bindingTrace:
    BindingTrace, files: Collection<KtFile>): AnalysisResult? {

        val diagnostics = bindingTrace.bindingContext.diagnostics
        return AnalysisResult.Companion.success(bindingContext, module)
    } 
}
But, I also want to modify this list like
Copy code
val newDiagnostics = diagnostics.filter { //myFilter }
And return this result back instead. Is something like this possible? Or is there any extension that allow me to modify diagnostics?
a
I have a solution witch is not perfect. Giving that the BindingContext is an interface, I can create and return my own version of binding context with filtered issue something like this
Copy code
override fun analysisCompleted(project: Project, module: ModuleDescriptor, bindingTrace:
    BindingTrace, files: Collection<KtFile>): AnalysisResult? {

        val stringBuilder = StringBuilder()

        val bindingContext = bindingTrace.bindingContext
        val newDiagnosticList = bindingContext.diagnostics.filter {
           //myfilter
        }

        val newDiagnostics = MyDiagnostics(bindingContext.diagnostics, newDiagnosticList)
        val newBindingContext = MyBindingContext(bindingContext, newDiagnostics)

        return AnalysisResult.Companion.success(newBindingContext, module)
    }
Here is
MyDiagnostics
implementation
Copy code
class MyDiagnostics(private val diagnostics: Diagnostics, private val newDiagnostics: Collection<Diagnostic>) : Diagnostics {
    override fun all(): Collection<Diagnostic> {
        return newDiagnostics
    }

    override fun forElement(psiElement: PsiElement): Collection<Diagnostic> {
        return diagnostics.forElement(psiElement)
    }

    override fun noSuppression(): Diagnostics {
        return diagnostics.noSuppression()
    }

    override val modificationTracker = diagnostics.modificationTracker

    override fun isEmpty() = diagnostics.isEmpty()

    override fun iterator() = diagnostics.iterator()
}
And
MyBindingContext
Copy code
class MyBindingContext(private val bindingContext: BindingContext,
private val newDiagnostics: Diagnostics): BindingContext {

    override fun <K : Any?, V : Any?> getKeys(p0: WritableSlice<K, V>?): Collection<K> {
        return bindingContext.getKeys(p0)
    }

    override fun getType(p0: KtExpression): KotlinType? {
        return bindingContext.getType(p0)
    }

    override fun <K : Any?, V : Any?> get(p0: ReadOnlySlice<K, V>?, p1: K): V? {
        return bindingContext.get(p0, p1)
    }

    override fun getDiagnostics(): Diagnostics {
        return newDiagnostics
    }

    override fun addOwnDataTo(p0: BindingTrace, p1: Boolean) {
        bindingContext.addOwnDataTo(p0, p1)
    }

    override fun <K : Any?, V : Any?> getSliceContents(p0: ReadOnlySlice<K, V>): ImmutableMap<K,
            V> {
        return bindingContext.getSliceContents(p0)
    }
}
This works but it has two problems, 1: I am changing static type of binding context and Diagnostics assuming compiler and other tools only rely on the interface (that may not be true) 2- It only shows me warning related to the source code and not all the warnings. I like to filter though all the compiler warnings
@raulraja thank for your suggestion. I changed my code to this
Copy code
val diagnostics: MutableDiagnosticsWithSuppression =
        BindingTraceContext::class.java.getDeclaredField("mutableDiagnostics").also { it.isAccessible = true }.get(bindingTrace) as MutableDiagnosticsWithSuppression
val mutableDiagnostics = diagnostics.getOwnDiagnostics() as ArrayList<Diagnostic>

mutableDiagnostics.removeIf { //myfilter }
And it works.
Do you know if I can use the same method to change the Severity of diagnostics?
r
yes as it’s a mutable list and you can extract them and create new ones from the existing ones like they do in their factories but not sure what implication it may have downstream in codegen since the compiler may expect certain diagnostic to be of a certain type