[clang-tdy] RFC: Support for plugin modules.

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[clang-tdy] RFC: Support for plugin modules.

Vassil Vassilev via cfe-dev
Dear List,

I've heard a few small discussions about this topic and they seem to be
positive so I thought I'd query it here to see what the consensus is.

The general idea is to add a `add-plugin` command line option to clang-
tidy, akin to the plugins clang supports. This will be used to load one
or more plugins that link additional ClangTidyModules to better enable
users to utilise their own custom clang-tidy checks.

Currently the only way to do that is to download the entire llvm
source, create the module and link it into clang-tidy the same way all
the built-in modules are linked.

Under this new proposal one could just get the required libraries. Then
build their module out of tree and tell clang-tidy to link at runtime
with `-add-plugin=<path-to-module>` command line option.

A typical modules source code could be as simple as this for just one
check

-----------------------------------------------------------------------

#include "ClangTidy.h"
#include "ClangTidyCheck.h"
#include "ClangTidyModule.h"
#include "ClangTidyModuleRegistry.h"

using namespace clang;
using namespace clang::tidy;
using namespace clang::ast_matchers;
using namespace llvm;

class AwesomeFunctionCheck : public ClangTidyCheck {
public:
  using ClangTidyCheck::ClangTidyCheck;

  void registerMatchers(MatchFinder *Finder) override {
    Finder->addMatcher(
        functionDecl(unless(matchesName("Awesome$"))).bind("Function"),
this);
  }
  void check(const MatchFinder::MatchResult &Result) override {
    const auto *Function =
Result.Nodes.getNodeAs<FunctionDecl>("Function");
    diag(Function->getLocation(), "Function '%0' is not sufficiently
awesome")
        << Function
        << FixItHint::CreateReplacement(
               Function->getLocation(),
               (Function->getName() + "Awesome").str());
  }
};

class MyPluginModule : public ClangTidyModule {
public:
  void addCheckFactories(ClangTidyCheckFactories &CheckFactories)
override {
    CheckFactories.registerCheck<AwesomeFunctionCheck>(
        "my-plugin-awesome-function");
  }
};

// Register the MyPluginModule using this statically initialized
variable.
static ClangTidyModuleRegistry::Add<MyPluginModule>
    X("my-plugin-module", "Adds my plugin checks.");

-----------------------------------------------------------------------

Obviously larger code bases may want multiple different checks in which
case it would be nicer to seperate the checks out into their own
implementation files (The way clang tidy is written now).

Once a plugin is linked its checks will still need to be turned on
using the `Checks` option from config files or the `checks` command
line option.

There will also need to be some documentation detailing how to create
plugins. https://clang.llvm.org/extra/clang-tidy/Contributing.html
already has some useful information but not everything needed for this purpose.

On the point of getting the required libraries I'm not too sure how
everything is packaged. From what I can see the clangTidy libraries are
packaged but the headers aren't. That would probably need addressing as
well.

Thanks for reading,
Nathan James

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [clang-tdy] RFC: Support for plugin modules.

Vassil Vassilev via cfe-dev
On Tue, Jun 23, 2020 at 8:42 AM Nathan James via cfe-dev
<[hidden email]> wrote:

>
> Dear List,
>
> I've heard a few small discussions about this topic and they seem to be
> positive so I thought I'd query it here to see what the consensus is.
>
> The general idea is to add a `add-plugin` command line option to clang-
> tidy, akin to the plugins clang supports. This will be used to load one
> or more plugins that link additional ClangTidyModules to better enable
> users to utilise their own custom clang-tidy checks.
>
> Currently the only way to do that is to download the entire llvm
> source, create the module and link it into clang-tidy the same way all
> the built-in modules are linked.
>
> Under this new proposal one could just get the required libraries. Then
> build their module out of tree and tell clang-tidy to link at runtime
> with `-add-plugin=<path-to-module>` command line option.
>
> A typical modules source code could be as simple as this for just one
> check
>
> -----------------------------------------------------------------------
>
> #include "ClangTidy.h"
> #include "ClangTidyCheck.h"
> #include "ClangTidyModule.h"
> #include "ClangTidyModuleRegistry.h"
>
> using namespace clang;
> using namespace clang::tidy;
> using namespace clang::ast_matchers;
> using namespace llvm;
>
> class AwesomeFunctionCheck : public ClangTidyCheck {
> public:
>   using ClangTidyCheck::ClangTidyCheck;
>
>   void registerMatchers(MatchFinder *Finder) override {
>     Finder->addMatcher(
>         functionDecl(unless(matchesName("Awesome$"))).bind("Function"),
> this);
>   }
>   void check(const MatchFinder::MatchResult &Result) override {
>     const auto *Function =
> Result.Nodes.getNodeAs<FunctionDecl>("Function");
>     diag(Function->getLocation(), "Function '%0' is not sufficiently
> awesome")
>         << Function
>         << FixItHint::CreateReplacement(
>                Function->getLocation(),
>                (Function->getName() + "Awesome").str());
>   }
> };
>
> class MyPluginModule : public ClangTidyModule {
> public:
>   void addCheckFactories(ClangTidyCheckFactories &CheckFactories)
> override {
>     CheckFactories.registerCheck<AwesomeFunctionCheck>(
>         "my-plugin-awesome-function");
>   }
> };
>
> // Register the MyPluginModule using this statically initialized
> variable.
> static ClangTidyModuleRegistry::Add<MyPluginModule>
>     X("my-plugin-module", "Adds my plugin checks.");
>
> -----------------------------------------------------------------------
>
> Obviously larger code bases may want multiple different checks in which
> case it would be nicer to seperate the checks out into their own
> implementation files (The way clang tidy is written now).
>
> Once a plugin is linked its checks will still need to be turned on
> using the `Checks` option from config files or the `checks` command
> line option.
>
> There will also need to be some documentation detailing how to create
> plugins. https://clang.llvm.org/extra/clang-tidy/Contributing.html
> already has some useful information but not everything needed for this purpose.
>
> On the point of getting the required libraries I'm not too sure how
> everything is packaged. From what I can see the clangTidy libraries are
> packaged but the headers aren't. That would probably need addressing as
> well.

I recently had a use case at work where we wanted to write a
clang-tidy plugin but couldn't due to the lack of infrastructure and
so we wound up writing a clang static analyzer plugin instead.
Unfortunately, because LLVM-based plugin systems do not work on
Windows, this functionality still wouldn't have helped us out for our
needs. That said, I'm still 100% behind the proposal -- even with the
general plugin limitations this is a feature I have often wished for
and been surprised wasn't supported.

~Aaron
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [clang-tdy] RFC: Support for plugin modules.

Vassil Vassilev via cfe-dev
There is an alternative solution that is already working. With Clang tarball release you can build custom clang-tidy with additional checks outside of LLVM sources like you do with any other Clang tool after https://reviews.llvm.org/D73236 and https://reviews.llvm.org/D73300. Minimal boilerplate looks like this:

#include <clang/Config/config.h>
#include <llvm/Support/Compiler.h>
#include <clang-tidy/tool/ClangTidyMain.h>

namespace clang {
namespace tidy {

// This anchor is used to force the linker to link the CustomModule.
extern volatile int CustomModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CustomModuleAnchorDestination =
    CustomModuleAnchorSource;

} // tidy
} // clang

int main(int argc, const char **argv) {
   return clang::tidy::clangTidyMain(argc, argv);
}

I think it is reasonable alternative to clang-tidy plugins that works everywhere. Anyway clang-tidy plugins are version dependent so they will work with almost the same version of Clang only.

On Tue, Jun 23, 2020 at 2:24 PM Aaron Ballman via cfe-dev <[hidden email]> wrote:
On Tue, Jun 23, 2020 at 8:42 AM Nathan James via cfe-dev
<[hidden email]> wrote:
>
> Dear List,
>
> I've heard a few small discussions about this topic and they seem to be
> positive so I thought I'd query it here to see what the consensus is.
>
> The general idea is to add a `add-plugin` command line option to clang-
> tidy, akin to the plugins clang supports. This will be used to load one
> or more plugins that link additional ClangTidyModules to better enable
> users to utilise their own custom clang-tidy checks.
>
> Currently the only way to do that is to download the entire llvm
> source, create the module and link it into clang-tidy the same way all
> the built-in modules are linked.
>
> Under this new proposal one could just get the required libraries. Then
> build their module out of tree and tell clang-tidy to link at runtime
> with `-add-plugin=<path-to-module>` command line option.
>
> A typical modules source code could be as simple as this for just one
> check
>
> -----------------------------------------------------------------------
>
> #include "ClangTidy.h"
> #include "ClangTidyCheck.h"
> #include "ClangTidyModule.h"
> #include "ClangTidyModuleRegistry.h"
>
> using namespace clang;
> using namespace clang::tidy;
> using namespace clang::ast_matchers;
> using namespace llvm;
>
> class AwesomeFunctionCheck : public ClangTidyCheck {
> public:
>   using ClangTidyCheck::ClangTidyCheck;
>
>   void registerMatchers(MatchFinder *Finder) override {
>     Finder->addMatcher(
>         functionDecl(unless(matchesName("Awesome$"))).bind("Function"),
> this);
>   }
>   void check(const MatchFinder::MatchResult &Result) override {
>     const auto *Function =
> Result.Nodes.getNodeAs<FunctionDecl>("Function");
>     diag(Function->getLocation(), "Function '%0' is not sufficiently
> awesome")
>         << Function
>         << FixItHint::CreateReplacement(
>                Function->getLocation(),
>                (Function->getName() + "Awesome").str());
>   }
> };
>
> class MyPluginModule : public ClangTidyModule {
> public:
>   void addCheckFactories(ClangTidyCheckFactories &CheckFactories)
> override {
>     CheckFactories.registerCheck<AwesomeFunctionCheck>(
>         "my-plugin-awesome-function");
>   }
> };
>
> // Register the MyPluginModule using this statically initialized
> variable.
> static ClangTidyModuleRegistry::Add<MyPluginModule>
>     X("my-plugin-module", "Adds my plugin checks.");
>
> -----------------------------------------------------------------------
>
> Obviously larger code bases may want multiple different checks in which
> case it would be nicer to seperate the checks out into their own
> implementation files (The way clang tidy is written now).
>
> Once a plugin is linked its checks will still need to be turned on
> using the `Checks` option from config files or the `checks` command
> line option.
>
> There will also need to be some documentation detailing how to create
> plugins. https://clang.llvm.org/extra/clang-tidy/Contributing.html
> already has some useful information but not everything needed for this purpose.
>
> On the point of getting the required libraries I'm not too sure how
> everything is packaged. From what I can see the clangTidy libraries are
> packaged but the headers aren't. That would probably need addressing as
> well.

I recently had a use case at work where we wanted to write a
clang-tidy plugin but couldn't due to the lack of infrastructure and
so we wound up writing a clang static analyzer plugin instead.
Unfortunately, because LLVM-based plugin systems do not work on
Windows, this functionality still wouldn't have helped us out for our
needs. That said, I'm still 100% behind the proposal -- even with the
general plugin limitations this is a feature I have often wished for
and been surprised wasn't supported.

~Aaron
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev