diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -389,9 +389,8 @@ llvm::InitLLVM X(argc, argv); // Enable help for -load option, if plugins are enabled. - cl::Option *load_opt = cl::getRegisteredOptions().lookup("load"); - if (load_opt) - load_opt->addCategory(ClangTidyCategory); + if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load")) + LoadOpt->addCategory(ClangTidyCategory); llvm::Expected OptionsParser = CommonOptionsParser::create(argc, argv, ClangTidyCategory, diff --git a/clang-tools-extra/docs/clang-tidy/Contributing.rst b/clang-tools-extra/docs/clang-tidy/Contributing.rst --- a/clang-tools-extra/docs/clang-tidy/Contributing.rst +++ b/clang-tools-extra/docs/clang-tidy/Contributing.rst @@ -418,18 +418,23 @@ Out-of-tree check plugins ------------------------- -If you want to develop this out-of-tree, the steps above are the largely same. -External to the clang-tidy build system, put all of the new code into a single -shared library. Build and link it against llvm, while allowing some symbols to -be undefined during linking, almost exactly as you would define a clang plugin. +Developing an out-of-tree check as a plugin largely follows the steps +outlined above. The plugin is a shared library whose code lives outside +the clang-tidy build system. Build and link this shared library against +LLVM as done for other kinds of Clang plugins. -Then we can run it by passing `-load` to `clang-tidy`, in addition to the name -of our new checks. +The plugin can be loaded by passing `-load` to `clang-tidy` in addition to the +names of the checks to enable. .. code-block:: console $ clang-tidy --checks=-*,my-explicit-constructor -list-checks -load myplugin.so +There is no expectations regarding ABI and API stability, so the plugin must be +compiled against the version of clang-tidy that will be loading the plugin. + +The plugins can use threads, TLS, or any other facilities available to in-tree +code which is accessible from the external headers. Running clang-tidy on LLVM -------------------------- diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -220,10 +220,11 @@ -checks=* to list all available checks. -load= - Load the dynamic object ``plugin``. This - object should register new static analyzer or clang-tidy passes. Once loaded, the object - will add new command line options to run - various analyses. To see the new complete - list of passes, use the + object should register new static analyzer + or clang-tidy passes. Once loaded, the + object will add new command line options + to run various analyses. To see the new + complete list of passes, use the :option:`--list-checks` and :option:`-load` options together. -p= - Build path diff --git a/clang-tools-extra/test/CMakeLists.txt b/clang-tools-extra/test/CMakeLists.txt --- a/clang-tools-extra/test/CMakeLists.txt +++ b/clang-tools-extra/test/CMakeLists.txt @@ -86,7 +86,7 @@ DEPENDS clang-tidy-headers) if(TARGET CTTestTidyModule) - list(APPEND CLANG_TOOLS_TEST_DEPS CTTestTidyModule) + list(APPEND CLANG_TOOLS_TEST_DEPS CTTestTidyModule LLVMHello) target_include_directories(CTTestTidyModule PUBLIC BEFORE "${CLANG_TOOLS_SOURCE_DIR}") if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN)) set(LLVM_LINK_COMPONENTS diff --git a/clang-tools-extra/test/clang-tidy/CTTestTidyModule.cpp b/clang-tools-extra/test/clang-tidy/CTTestTidyModule.cpp --- a/clang-tools-extra/test/clang-tidy/CTTestTidyModule.cpp +++ b/clang-tools-extra/test/clang-tidy/CTTestTidyModule.cpp @@ -1,7 +1,11 @@ // REQUIRES: plugins -// RUN: clang-tidy -checks='-*,mytest' --list-checks -load %llvmshlibdir/CTTestTidyModule%pluginext | FileCheck %s -// CHECK: Enabled checks: -// CHECK-NEXT: mytest +// RUN: clang-tidy -checks='-*,mytest*' --list-checks -load %llvmshlibdir/CTTestTidyModule%pluginext -load %llvmshlibdir/LLVMHello%pluginext | FileCheck --check-prefix=CHECK-LIST %s +// CHECK-LIST: Enabled checks: +// CHECK-LIST-NEXT: mytest1 +// CHECK-LIST-NEXT: mytest2 +// RUN: clang-tidy -checks='-*,mytest*,misc-definitions-in-headers' -load %llvmshlibdir/CTTestTidyModule%pluginext /dev/null -- -xc 2>&1 | FileCheck %s +// CHECK: 3 warnings generated. +// CHECK-NEXT: warning: mytest success [misc-definitions-in-headers,mytest1,mytest2] #include "clang-tidy/ClangTidy.h" #include "clang-tidy/ClangTidyCheck.h" @@ -21,8 +25,15 @@ MyTestCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} - //void registerMatchers(ast_matchers::MatchFinder *Finder) override; - //void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override { + Finder->addMatcher(translationUnitDecl().bind("tu"), this); + } + + void check(const ast_matchers::MatchFinder::MatchResult &Result) override { + auto S = Result.Nodes.getNodeAs("tu"); + if (S) + diag("mytest success"); + } private: }; @@ -30,21 +41,26 @@ class CTTestModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck("mytest"); + CheckFactories.registerCheck("mytest1"); + CheckFactories.registerCheck("mytest2"); + // intentionally collide with an existing test name, overriding it + CheckFactories.registerCheck("misc-definitions-in-headers"); } }; } // namespace -namespace clang { -namespace tidy { - +namespace tidy1 { // Register the CTTestTidyModule using this statically initialized variable. static ClangTidyModuleRegistry::Add<::CTTestModule> X("mytest-module", "Adds my checks."); +} // namespace tidy1 + +namespace tidy2 { +// intentionally collide with an existing test group name, merging with it +static ClangTidyModuleRegistry::Add<::CTTestModule> + X("misc-module", "Adds miscellaneous lint checks."); +} // namespace tidy2 // This anchor is used to force the linker to link in the generated object file // and thus register the CTTestModule. volatile int CTTestModuleAnchorSource = 0; - -} // namespace tidy -} // namespace clang