Thanks for the fast response. I totally agree with your point of the disadvantages of using plugins. My question was exactly how to avoid using plugins. Maybe I had some misunderstanding, does the "plugin" you talked about not only include dynamic libraries, but also include registering checkers in programs that uses clang as a library?
For the 2 solutions you propsed, they are good suggestions, but unfortunately they won't work in our specific situation. The checker I am adding is very company specific, and involves specific class in company's code base; I believe it is impossible to make it public, because it will reveal company's internal codebase; also it is useless to public because the situation it tries to analyze is very ad-hoc, company specific, thus won't apply to other people's code at all.
As for rebasing against upstream, that's not feasible as well because this involves maintenance cost. I am at a large company where I don't have control or any influence on the process it sync third-party libraries with upstream, neither does the clang-tidy team of our company. That's why they suggest me doing it upstream.
The 3 approaches in my original question was in fact about modifying upstream to expose the checker registration process, so that not only us, but other people could also benefit from it. If there is such an API, then in a program that uses clang as a library, they can call the exposed API to register their own checker, before using AnalysisConsumer to do a static analysis.
Neither of the 3 approaches I proposed uses plugin architecture. It is just caller program who instantiates checker (or some form of checker factory), then hands it over to Clang, therefore there is no need to worry about how Clang can find the libraries.
I am more then happy if there are other ideas and I can contribute my manpower to coming up with some patches.