In order to report an error if a class doesn't hav...
# compiler
m
In order to report an error if a class doesn't have a primary constructor, I understand that my
FirAdditionalCheckersExtension
should override
declarationCheckers: DeclarationCheckers
with an instance that populates one of the following properties:
Copy code
open val classLikeCheckers: Set<FirClassLikeChecker> = emptySet()
open val classCheckers: Set<FirClassChecker> = emptySet()
open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet()
open val constructorCheckers: Set<FirConstructorChecker> = emptySet()
But which one and why?
d
Each checker type gets invoked on every declaration of the corresponding type. So, for example, for given
FirRegularClass
would be executed checkers from the following lists:
[regularClassCheckers, classCheckers, classLikeCheckers, declarationCheckers]
.
Considering that you want to check only classes if there is or isn't a primary constructor, it should be
FirRegularClassChecker
(or
FirClassChecker
if you also want to check anonymous objects for some reason). It definitely shouldn't be a
FirConstructorChecker
, as it wouldn't be invoked if there is no constructor in the class.
m
Copy code
class MyFirAdditionalCheckersExtension(
    session: FirSession,
    mppKind: MppCheckerKind,
): FirAdditionalCheckersExtension(session) {
    override val declarationCheckers: DeclarationCheckers = object: DeclarationCheckers() {
        override val regularClassCheckers = setOf(object: FirRegularClassChecker(mppKind) {
            context(context: CheckerContext, reporter: DiagnosticReporter)
            override fun check(declaration: FirRegularClass) {
                TODO("Not yet implemented")
            }
        })
    }
}
So should I do this? Am I supposed to
override val regularClassCheckers
?
Copy code
abstract class DeclarationCheckers {
    // ...
    open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet()
I was going to populate
this.regularClassCheckers
but it’s not a
MutableSet<_>
and I couldn’t call
add
on it. The abstract base class is meant to allocate an unused empty set and my derived class is expected to allocate again?
d
Yep, that's right. My only advice would be to make the checker itself a proper top-level object, not a deeply anonymous object.
Here is an example how this extension is defined in the atomicfu plugin: link.
The abstract base class is meant to allocate an unused empty set and my derived class is expected to allocate again?
Good spot, actually. It makes sense to replace all these
= emptySet()
in the base checkers container with
get() = emptySet()
.
m
Once I have a
FirAdditionalCheckersExtension
that ensures that every relevant class has a primary constructor, is it safe to call
classSymbol.primaryConstructorIfAny(this.session)!!
in my
FirDeclarationGenerationExtension
?
d
Nope, it's not safe. Checkers are executed last among all frontend extensions.
m
It feels like everything is out to get me! Thank you for the heads-up regardless
👍 1