NagyDonat wrote:

> I'm happy as this PR looks right now, except for having that backward 
> compatibility overload for plugins.
> We can just move on with life and let them migrate once the next clang is 
> out. To me, the upgrade path looks straightforward and this isn't the only 
> API they will need to adjust anyway. They should brace for impact.

I first created commit 
https://github.com/llvm/llvm-project/pull/139256/commits/84eb5afa867f8f12db259053cb768919e0418ea8
 which eliminated the compatibility overloads and introduced `addMockChecker` 
to give a name to a pattern that appeared many times. However, as updated the 
doc comments, I realized that the fully general `addChecker` is needlessly 
verbose and hostile for plugin authors, so I created commit 
https://github.com/llvm/llvm-project/pull/139256/commits/04bfbf1551fa34602f54a85b45154bbaab4551ce
 which introduces other overloads that are more suitable for plugins.

Unfortunately these changes add ±100 changed lines, which makes this commit 
even larger -- but at least I got to fix some minor problems (e.g. obsolete 
docs and one case of the `mutable std::unique_ptr<BugType>` disease) in the 
plugin test code.

-------

> Could you give an example when it's misleading and not refers to a class 
> name? I figured the tablegen construct we have ensures this.

The second argument of the `CHECKER` macro is customarily called `CLASS`, but 
in fact it is a unique identifier of the particular checker fronted which is 
only used in the macro magic that assigns unique names to the registration 
methods.  In each checker family there is at most one checker whose `CLASS` 
matches the actual class name, because otherwise it would be impossible to 
define separate registration methods for them. (I also looked at the tablegen 
code in clang/utils/TableGen/ClangSACheckersEmitter.cpp and nothing tries to 
check that it is a valid class name.) As a concrete example, the `Checkers.inc` 
lines for the divzero checkers look like
```c++
CHECKER("core.DivideZero", DivZeroChecker, "Check for division by zero", 
"https://...";, false)
CHECKER("optin.taint.TaintedDiv", TaintedDivChecker, "Check for divisions ...", 
"https://...";, false)                                                           
                         
```
and you can see that `TaintedDivChecker` is not a real class name.

> We should be fine touching the plugin registration. This shouldn't be 
> disruptive.

Ok, noted -- I wasn't familiar with the plugin ecosystem.

> WDYM by that this identifier is not stable?

Under this plan 6, the "identifier" = debug name of the checker family is the 
`CLASS` field of the sub-checker (=CheckerFrontend) which is enabled first (on 
that particular run).

As the `CLASS`es of the subcheckers are necessarily all different, enabling 
different sub-checkers always changes the debug name unless dependency 
relationships guarantee that the first subchecker is always enabled. However, 
in this "first subchecker is a common dependency of all other subcheckers" 
architecture the first subchecker does _nothing_, so it's just a very complex 
form boilerplate.

> We could have a tablegen property like ImplementedBy<"MyChecker"> for the few 
> checker families we currently have, and say that by default they are 
> implemented by CLASS.

As I described above, we would need these `ImplementedBy<"MyChecker">` markers 
in *all* checker families for *almost all* subcheckers (because only one 
subchecker can own the real `CLASS` name) -- which would be more boilerplate 
than just declaring one `StringRef getDebugName() override {return 
"SomeCheckerFamily";}` per checker family.

--------

**Based on these, I'm still pleading you to reconsider your rejection of option 
1, because it is still the most clear solution to ensure that `getDebugName()` 
consistently returns the class name.**

If the class name of the `CheckerFamily` is not stringified automatically via 
option 2 (which you also reject), then it must be written down *somewhere*. 
Directly placing it at its single point of use (`getDebugName()`) is much 
simpler than hiding it away in the highly magical `Checkers.td` definitions and 
then threading yet another "move this value from _here_ to _there_" sphagetti 
into the already tangled checker registration code. For a novice checker 
developer who is familiar with C++, the task "provide a trivial implementation 
for this virtual method" is much easier than "put yet another field into this 
project-specific magical metadata file"!

Moreover, placing the class name into the current CheckerFrontend-centric 
`Checkers.td` (in a stable way that doesn't depend on the set of subcheckers 
enabled by the user) is not an easy task:
- If each checker family has a "modeling checker" as its first subchecker which 
is a common dependency of all the "real" checkers, then the full modeling 
checker (two registration method + `Checker<>` specification in `Checkers.td` + 
dependency relationships) **is boilerplate** – lots of boilerplate – which 
could be avoided in all other implementations.
- If `Checker<>` specification in `Checker.td` includes an 
`ImplementedBy<"MyChecker">` to correct situations where `CLASS` differs from 
the real class name, then each checker family requires _(N-1)_ of these 
`ImplementedBy` tags where $N$ is the number of subcheckers. If $N > 2$, this 
is more verbose than defining just one method override.
- If we update `Checkers.td` to ensure that the `CLASS` field always contains 
the real class name, then we need to add an extra field which can be used to 
distinguish the names of the register methods. Adding one 
`RegisterNameTag<"Foo">` to _each_ checker part (possibly excluding one) is 
more verbose than defining just one method override for the whole family.

I'm also suggesting plan 1, because it is a good "placeholder" that leaves 
space for later improvements that could provide an actually _good_ way of 
injecting the checker class name. For example in the future we could move 
towards my "alternative" plan, where I suggested that we should
> Extend the format of `Checkers.td` to support three kinds of checker entities:
>  -    ModelingCheckers that have a debug name and can be activated as 
> dependencies (and probably they can also have dependencies);
>  -    ReportingCheckers that have a user-facing name, can be enabled or 
> disabled by the user, can have checker options and depend on one or more 
> ModelingCheckers;
>  -    Checkers which are just a shortcut for introducing a ModelingChecker 
> and a single ReportingChecker that depends on it.

In this system each checker family would correspond to a single lightweight 
`ModelingChecker` entry in `Checkers.td` from which we could easily query the 
class name.



https://github.com/llvm/llvm-project/pull/139256
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to