|  | ================ | 
|  | Getting Involved | 
|  | ================ | 
|  |  | 
|  | :program:`clang-tidy` has several own checks and can run Clang static analyzer | 
|  | checks, but its power is in the ability to easily write custom checks. | 
|  |  | 
|  | Checks are organized in modules, which can be linked into :program:`clang-tidy` | 
|  | with minimal or no code changes in :program:`clang-tidy`. | 
|  |  | 
|  | Checks can plug into the analysis on the preprocessor level using `PPCallbacks`_ | 
|  | or on the AST level using `AST Matchers`_. When an error is found, checks can | 
|  | report them in a way similar to how Clang diagnostics work. A fix-it hint can be | 
|  | attached to a diagnostic message. | 
|  |  | 
|  | The interface provided by :program:`clang-tidy` makes it easy to write useful | 
|  | and precise checks in just a few lines of code. If you have an idea for a good | 
|  | check, the rest of this document explains how to do this. | 
|  |  | 
|  | There are a few tools particularly useful when developing clang-tidy checks: | 
|  | * ``add_new_check.py`` is a script to automate the process of adding a new | 
|  | check, it will create the check, update the CMake file and create a test; | 
|  | * ``rename_check.py`` does what the script name suggests, renames an existing | 
|  | check; | 
|  | * :program:`clang-query` is invaluable for interactive prototyping of AST | 
|  | matchers and exploration of the Clang AST; | 
|  | * `clang-check`_ with the ``-ast-dump`` (and optionally ``-ast-dump-filter``) | 
|  | provides a convenient way to dump AST of a C++ program. | 
|  |  | 
|  | If CMake is configured with ``CLANG_ENABLE_STATIC_ANALYZER``, | 
|  | :program:`clang-tidy` will not be built with support for the | 
|  | ``clang-analyzer-*`` checks or the ``mpi-*`` checks. | 
|  |  | 
|  |  | 
|  | .. _AST Matchers: https://clang.llvm.org/docs/LibASTMatchers.html | 
|  | .. _PPCallbacks: https://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html | 
|  | .. _clang-check: https://clang.llvm.org/docs/ClangCheck.html | 
|  |  | 
|  |  | 
|  | Choosing the Right Place for your Check | 
|  | --------------------------------------- | 
|  |  | 
|  | If you have an idea of a check, you should decide whether it should be | 
|  | implemented as a: | 
|  |  | 
|  | + *Clang diagnostic*: if the check is generic enough, targets code patterns that | 
|  | most probably are bugs (rather than style or readability issues), can be | 
|  | implemented effectively and with extremely low false positive rate, it may | 
|  | make a good Clang diagnostic. | 
|  |  | 
|  | + *Clang static analyzer check*: if the check requires some sort of control flow | 
|  | analysis, it should probably be implemented as a static analyzer check. | 
|  |  | 
|  | + *clang-tidy check* is a good choice for linter-style checks, checks that are | 
|  | related to a certain coding style, checks that address code readability, etc. | 
|  |  | 
|  |  | 
|  | Preparing your Workspace | 
|  | ------------------------ | 
|  |  | 
|  | If you are new to LLVM development, you should read the `Getting Started with | 
|  | the LLVM System`_, `Using Clang Tools`_ and `How To Setup Clang Tooling For | 
|  | LLVM`_ documents to check out and build LLVM, Clang and Clang Extra Tools with | 
|  | CMake. | 
|  |  | 
|  | Once you are done, change to the ``llvm/clang-tools-extra`` directory, and | 
|  | let's start! | 
|  |  | 
|  | .. _Getting Started with the LLVM System: https://llvm.org/docs/GettingStarted.html | 
|  | .. _Using Clang Tools: https://clang.llvm.org/docs/ClangTools.html | 
|  | .. _How To Setup Clang Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html | 
|  |  | 
|  |  | 
|  | The Directory Structure | 
|  | ----------------------- | 
|  |  | 
|  | :program:`clang-tidy` source code resides in the | 
|  | ``llvm/clang-tools-extra`` directory and is structured as follows: | 
|  |  | 
|  | :: | 
|  |  | 
|  | clang-tidy/                       # Clang-tidy core. | 
|  | |-- ClangTidy.h                   # Interfaces for users. | 
|  | |-- ClangTidyCheck.h              # Interfaces for checks. | 
|  | |-- ClangTidyModule.h             # Interface for clang-tidy modules. | 
|  | |-- ClangTidyModuleRegistry.h     # Interface for registering of modules. | 
|  | ... | 
|  | |-- google/                       # Google clang-tidy module. | 
|  | |-+ | 
|  | |-- GoogleTidyModule.cpp | 
|  | |-- GoogleTidyModule.h | 
|  | ... | 
|  | |-- llvm/                         # LLVM clang-tidy module. | 
|  | |-+ | 
|  | |-- LLVMTidyModule.cpp | 
|  | |-- LLVMTidyModule.h | 
|  | ... | 
|  | |-- objc/                         # Objective-C clang-tidy module. | 
|  | |-+ | 
|  | |-- ObjCTidyModule.cpp | 
|  | |-- ObjCTidyModule.h | 
|  | ... | 
|  | |-- tool/                         # Sources of the clang-tidy binary. | 
|  | ... | 
|  | test/clang-tidy/                  # Integration tests. | 
|  | ... | 
|  | unittests/clang-tidy/             # Unit tests. | 
|  | |-- ClangTidyTest.h | 
|  | |-- GoogleModuleTest.cpp | 
|  | |-- LLVMModuleTest.cpp | 
|  | |-- ObjCModuleTest.cpp | 
|  | ... | 
|  |  | 
|  |  | 
|  | Writing a clang-tidy Check | 
|  | -------------------------- | 
|  |  | 
|  | So you have an idea of a useful check for :program:`clang-tidy`. | 
|  |  | 
|  | First, if you're not familiar with LLVM development, read through the `Getting | 
|  | Started with LLVM`_ document for instructions on setting up your workflow and | 
|  | the `LLVM Coding Standards`_ document to familiarize yourself with the coding | 
|  | style used in the project. For code reviews we mostly use `LLVM Phabricator`_. | 
|  |  | 
|  | .. _Getting Started with LLVM: https://llvm.org/docs/GettingStarted.html | 
|  | .. _LLVM Coding Standards: https://llvm.org/docs/CodingStandards.html | 
|  | .. _LLVM Phabricator: https://llvm.org/docs/Phabricator.html | 
|  |  | 
|  | Next, you need to decide which module the check belongs to. Modules | 
|  | are located in subdirectories of `clang-tidy/ | 
|  | <https://github.com/llvm/llvm-project/tree/master/clang-tools-extra/clang-tidy/>`_ | 
|  | and contain checks targeting a certain aspect of code quality (performance, | 
|  | readability, etc.), certain coding style or standard (Google, LLVM, CERT, etc.) | 
|  | or a widely used API (e.g. MPI). Their names are same as user-facing check | 
|  | groups names described :ref:`above <checks-groups-table>`. | 
|  |  | 
|  | After choosing the module and the name for the check, run the | 
|  | ``clang-tidy/add_new_check.py`` script to create the skeleton of the check and | 
|  | plug it to :program:`clang-tidy`. It's the recommended way of adding new checks. | 
|  |  | 
|  | If we want to create a `readability-awesome-function-names`, we would run: | 
|  |  | 
|  | .. code-block:: console | 
|  |  | 
|  | $ clang-tidy/add_new_check.py readability awesome-function-names | 
|  |  | 
|  |  | 
|  | The ``add_new_check.py`` script will: | 
|  | * create the class for your check inside the specified module's directory and | 
|  | register it in the module and in the build system; | 
|  | * create a lit test file in the ``test/clang-tidy/`` directory; | 
|  | * create a documentation file and include it into the | 
|  | ``docs/clang-tidy/checks/list.rst``. | 
|  |  | 
|  | Let's see in more detail at the check class definition: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | ... | 
|  |  | 
|  | #include "../ClangTidyCheck.h" | 
|  |  | 
|  | namespace clang { | 
|  | namespace tidy { | 
|  | namespace readability { | 
|  |  | 
|  | ... | 
|  | class AwesomeFunctionNamesCheck : public ClangTidyCheck { | 
|  | public: | 
|  | AwesomeFunctionNamesCheck(StringRef Name, ClangTidyContext *Context) | 
|  | : ClangTidyCheck(Name, Context) {} | 
|  | void registerMatchers(ast_matchers::MatchFinder *Finder) override; | 
|  | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | 
|  | }; | 
|  |  | 
|  | } // namespace readability | 
|  | } // namespace tidy | 
|  | } // namespace clang | 
|  |  | 
|  | ... | 
|  |  | 
|  | Constructor of the check receives the ``Name`` and ``Context`` parameters, and | 
|  | must forward them to the ``ClangTidyCheck`` constructor. | 
|  |  | 
|  | In our case the check needs to operate on the AST level and it overrides the | 
|  | ``registerMatchers`` and ``check`` methods. If we wanted to analyze code on the | 
|  | preprocessor level, we'd need instead to override the ``registerPPCallbacks`` | 
|  | method. | 
|  |  | 
|  | In the ``registerMatchers`` method we create an AST Matcher (see `AST Matchers`_ | 
|  | for more information) that will find the pattern in the AST that we want to | 
|  | inspect. The results of the matching are passed to the ``check`` method, which | 
|  | can further inspect them and report diagnostics. | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | using namespace ast_matchers; | 
|  |  | 
|  | void AwesomeFunctionNamesCheck::registerMatchers(MatchFinder *Finder) { | 
|  | Finder->addMatcher(functionDecl().bind("x"), this); | 
|  | } | 
|  |  | 
|  | void AwesomeFunctionNamesCheck::check(const MatchFinder::MatchResult &Result) { | 
|  | const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x"); | 
|  | if (MatchedDecl->getName().startswith("awesome_")) | 
|  | return; | 
|  | diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome") | 
|  | << MatchedDecl | 
|  | << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_"); | 
|  | } | 
|  |  | 
|  | (If you want to see an example of a useful check, look at | 
|  | `clang-tidy/google/ExplicitConstructorCheck.h | 
|  | <https://github.com/llvm/llvm-project/blob/master/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.h>`_ | 
|  | and `clang-tidy/google/ExplicitConstructorCheck.cpp | 
|  | <https://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp>`_). | 
|  |  | 
|  |  | 
|  | Registering your Check | 
|  | ---------------------- | 
|  |  | 
|  | (The ``add_new_check.py`` takes care of registering the check in an existing | 
|  | module. If you want to create a new module or know the details, read on.) | 
|  |  | 
|  | The check should be registered in the corresponding module with a distinct name: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | class MyModule : public ClangTidyModule { | 
|  | public: | 
|  | void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { | 
|  | CheckFactories.registerCheck<ExplicitConstructorCheck>( | 
|  | "my-explicit-constructor"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | Now we need to register the module in the ``ClangTidyModuleRegistry`` using a | 
|  | statically initialized variable: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | static ClangTidyModuleRegistry::Add<MyModule> X("my-module", | 
|  | "Adds my lint checks."); | 
|  |  | 
|  |  | 
|  | When using LLVM build system, we need to use the following hack to ensure the | 
|  | module is linked into the :program:`clang-tidy` binary: | 
|  |  | 
|  | Add this near the ``ClangTidyModuleRegistry::Add<MyModule>`` variable: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // This anchor is used to force the linker to link in the generated object file | 
|  | // and thus register the MyModule. | 
|  | volatile int MyModuleAnchorSource = 0; | 
|  |  | 
|  | And this to the main translation unit of the :program:`clang-tidy` binary (or | 
|  | the binary you link the ``clang-tidy`` library in) | 
|  | ``clang-tidy/tool/ClangTidyMain.cpp``: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // This anchor is used to force the linker to link the MyModule. | 
|  | extern volatile int MyModuleAnchorSource; | 
|  | static int MyModuleAnchorDestination = MyModuleAnchorSource; | 
|  |  | 
|  |  | 
|  | Configuring Checks | 
|  | ------------------ | 
|  |  | 
|  | If a check needs configuration options, it can access check-specific options | 
|  | using the ``Options.get<Type>("SomeOption", DefaultValue)`` call in the check | 
|  | constructor. In this case the check should also override the | 
|  | ``ClangTidyCheck::storeOptions`` method to make the options provided by the | 
|  | check discoverable. This method lets :program:`clang-tidy` know which options | 
|  | the check implements and what the current values are (e.g. for the | 
|  | ``-dump-config`` command line option). | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | class MyCheck : public ClangTidyCheck { | 
|  | const unsigned SomeOption1; | 
|  | const std::string SomeOption2; | 
|  |  | 
|  | public: | 
|  | MyCheck(StringRef Name, ClangTidyContext *Context) | 
|  | : ClangTidyCheck(Name, Context), | 
|  | SomeOption(Options.get("SomeOption1", -1U)), | 
|  | SomeOption(Options.get("SomeOption2", "some default")) {} | 
|  |  | 
|  | void storeOptions(ClangTidyOptions::OptionMap &Opts) override { | 
|  | Options.store(Opts, "SomeOption1", SomeOption1); | 
|  | Options.store(Opts, "SomeOption2", SomeOption2); | 
|  | } | 
|  | ... | 
|  |  | 
|  | Assuming the check is registered with the name "my-check", the option can then | 
|  | be set in a ``.clang-tidy`` file in the following way: | 
|  |  | 
|  | .. code-block:: yaml | 
|  |  | 
|  | CheckOptions: | 
|  | - key: my-check.SomeOption1 | 
|  | value: 123 | 
|  | - key: my-check.SomeOption2 | 
|  | value: 'some other value' | 
|  |  | 
|  | If you need to specify check options on a command line, you can use the inline | 
|  | YAML format: | 
|  |  | 
|  | .. code-block:: console | 
|  |  | 
|  | $ clang-tidy -config="{CheckOptions: [{key: a, value: b}, {key: x, value: y}]}" ... | 
|  |  | 
|  |  | 
|  | Testing Checks | 
|  | -------------- | 
|  |  | 
|  | To run tests for :program:`clang-tidy` use the command: | 
|  |  | 
|  | .. code-block:: console | 
|  |  | 
|  | $ ninja check-clang-tools | 
|  |  | 
|  | :program:`clang-tidy` checks can be tested using either unit tests or | 
|  | `lit`_ tests. Unit tests may be more convenient to test complex replacements | 
|  | with strict checks. `Lit`_ tests allow using partial text matching and regular | 
|  | expressions which makes them more suitable for writing compact tests for | 
|  | diagnostic messages. | 
|  |  | 
|  | The ``check_clang_tidy.py`` script provides an easy way to test both | 
|  | diagnostic messages and fix-its. It filters out ``CHECK`` lines from the test | 
|  | file, runs :program:`clang-tidy` and verifies messages and fixes with two | 
|  | separate `FileCheck`_ invocations: once with FileCheck's directive | 
|  | prefix set to ``CHECK-MESSAGES``, validating the diagnostic messages, | 
|  | and once with the directive prefix set to ``CHECK-FIXES``, running | 
|  | against the fixed code (i.e., the code after generated fix-its are | 
|  | applied). In particular, ``CHECK-FIXES:`` can be used to check | 
|  | that code was not modified by fix-its, by checking that it is present | 
|  | unchanged in the fixed code. The full set of `FileCheck`_ directives | 
|  | is available (e.g., ``CHECK-MESSAGES-SAME:``, ``CHECK-MESSAGES-NOT:``), though | 
|  | typically the basic ``CHECK`` forms (``CHECK-MESSAGES`` and ``CHECK-FIXES``) | 
|  | are sufficient for clang-tidy tests. Note that the `FileCheck`_ | 
|  | documentation mostly assumes the default prefix (``CHECK``), and hence | 
|  | describes the directive as ``CHECK:``, ``CHECK-SAME:``, ``CHECK-NOT:``, etc. | 
|  | Replace ``CHECK`` by either ``CHECK-FIXES`` or ``CHECK-MESSAGES`` for | 
|  | clang-tidy tests. | 
|  |  | 
|  | An additional check enabled by ``check_clang_tidy.py`` ensures that | 
|  | if `CHECK-MESSAGES:` is used in a file then every warning or error | 
|  | must have an associated CHECK in that file. Or, you can use ``CHECK-NOTES:`` | 
|  | instead, if you want to **also** ensure that all the notes are checked. | 
|  |  | 
|  | To use the ``check_clang_tidy.py`` script, put a .cpp file with the | 
|  | appropriate ``RUN`` line in the ``test/clang-tidy`` directory. Use | 
|  | ``CHECK-MESSAGES:`` and ``CHECK-FIXES:`` lines to write checks against | 
|  | diagnostic messages and fixed code. | 
|  |  | 
|  | It's advised to make the checks as specific as possible to avoid checks matching | 
|  | to incorrect parts of the input. Use ``[[@LINE+X]]``/``[[@LINE-X]]`` | 
|  | substitutions and distinct function and variable names in the test code. | 
|  |  | 
|  | Here's an example of a test using the ``check_clang_tidy.py`` script (the full | 
|  | source code is at `test/clang-tidy/google-readability-casting.cpp`_): | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // RUN: %check_clang_tidy %s google-readability-casting %t | 
|  |  | 
|  | void f(int a) { | 
|  | int b = (int)a; | 
|  | // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant cast to the same type [google-readability-casting] | 
|  | // CHECK-FIXES: int b = a; | 
|  | } | 
|  |  | 
|  | To check more than one scenario in the same test file use | 
|  | ``-check-suffix=SUFFIX-NAME`` on ``check_clang_tidy.py`` command line or | 
|  | ``-check-suffixes=SUFFIX-NAME-1,SUFFIX-NAME-2,...``. | 
|  | With ``-check-suffix[es]=SUFFIX-NAME`` you need to replace your ``CHECK-*`` | 
|  | directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``. | 
|  |  | 
|  | Here's an example: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // RUN: %check_clang_tidy -check-suffix=USING-A %s misc-unused-using-decls %t -- -- -DUSING_A | 
|  | // RUN: %check_clang_tidy -check-suffix=USING-B %s misc-unused-using-decls %t -- -- -DUSING_B | 
|  | // RUN: %check_clang_tidy %s misc-unused-using-decls %t | 
|  | ... | 
|  | // CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}} | 
|  | // CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}} | 
|  | // CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}} | 
|  | // CHECK-FIXES-USING-A-NOT: using a::A;$ | 
|  | // CHECK-FIXES-USING-B-NOT: using a::B;$ | 
|  | // CHECK-FIXES-NOT: using a::C;$ | 
|  |  | 
|  |  | 
|  | There are many dark corners in the C++ language, and it may be difficult to make | 
|  | your check work perfectly in all cases, especially if it issues fix-it hints. The | 
|  | most frequent pitfalls are macros and templates: | 
|  |  | 
|  | 1. code written in a macro body/template definition may have a different meaning | 
|  | depending on the macro expansion/template instantiation; | 
|  | 2. multiple macro expansions/template instantiations may result in the same code | 
|  | being inspected by the check multiple times (possibly, with different | 
|  | meanings, see 1), and the same warning (or a slightly different one) may be | 
|  | issued by the check multiple times; :program:`clang-tidy` will deduplicate | 
|  | _identical_ warnings, but if the warnings are slightly different, all of them | 
|  | will be shown to the user (and used for applying fixes, if any); | 
|  | 3. making replacements to a macro body/template definition may be fine for some | 
|  | macro expansions/template instantiations, but easily break some other | 
|  | expansions/instantiations. | 
|  |  | 
|  | .. _lit: https://llvm.org/docs/CommandGuide/lit.html | 
|  | .. _FileCheck: https://llvm.org/docs/CommandGuide/FileCheck.html | 
|  | .. _test/clang-tidy/google-readability-casting.cpp: https://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/test/clang-tidy/google-readability-casting.cpp | 
|  |  | 
|  |  | 
|  | Running clang-tidy on LLVM | 
|  | -------------------------- | 
|  |  | 
|  | To test a check it's best to try it out on a larger code base. LLVM and Clang | 
|  | are the natural targets as you already have the source code around. The most | 
|  | convenient way to run :program:`clang-tidy` is with a compile command database; | 
|  | CMake can automatically generate one, for a description of how to enable it see | 
|  | `How To Setup Clang Tooling For LLVM`_. Once ``compile_commands.json`` is in | 
|  | place and a working version of :program:`clang-tidy` is in ``PATH`` the entire | 
|  | code base can be analyzed with ``clang-tidy/tool/run-clang-tidy.py``. The script | 
|  | executes :program:`clang-tidy` with the default set of checks on every | 
|  | translation unit in the compile command database and displays the resulting | 
|  | warnings and errors. The script provides multiple configuration flags. | 
|  |  | 
|  | .. _How To Setup Clang Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html | 
|  |  | 
|  |  | 
|  | * The default set of checks can be overridden using the ``-checks`` argument, | 
|  | taking the identical format as :program:`clang-tidy` does. For example | 
|  | ``-checks=-*,modernize-use-override`` will run the ``modernize-use-override`` | 
|  | check only. | 
|  |  | 
|  | * To restrict the files examined you can provide one or more regex arguments | 
|  | that the file names are matched against. | 
|  | ``run-clang-tidy.py clang-tidy/.*Check\.cpp`` will only analyze clang-tidy | 
|  | checks. It may also be necessary to restrict the header files warnings are | 
|  | displayed from using the ``-header-filter`` flag. It has the same behavior | 
|  | as the corresponding :program:`clang-tidy` flag. | 
|  |  | 
|  | * To apply suggested fixes ``-fix`` can be passed as an argument. This gathers | 
|  | all changes in a temporary directory and applies them. Passing ``-format`` | 
|  | will run clang-format over changed lines. | 
|  |  | 
|  |  | 
|  | On checks profiling | 
|  | ------------------- | 
|  |  | 
|  | :program:`clang-tidy` can collect per-check profiling info, and output it | 
|  | for each processed source file (translation unit). | 
|  |  | 
|  | To enable profiling info collection, use the ``-enable-check-profile`` argument. | 
|  | The timings will be output to ``stderr`` as a table. Example output: | 
|  |  | 
|  | .. code-block:: console | 
|  |  | 
|  | $ clang-tidy -enable-check-profile -checks=-*,readability-function-size source.cpp | 
|  | ===-------------------------------------------------------------------------=== | 
|  | clang-tidy checks profiling | 
|  | ===-------------------------------------------------------------------------=== | 
|  | Total Execution Time: 1.0282 seconds (1.0258 wall clock) | 
|  |  | 
|  | ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name --- | 
|  | 0.9136 (100.0%)   0.1146 (100.0%)   1.0282 (100.0%)   1.0258 (100.0%)  readability-function-size | 
|  | 0.9136 (100.0%)   0.1146 (100.0%)   1.0282 (100.0%)   1.0258 (100.0%)  Total | 
|  |  | 
|  | It can also store that data as JSON files for further processing. Example output: | 
|  |  | 
|  | .. code-block:: console | 
|  |  | 
|  | $ clang-tidy -enable-check-profile -store-check-profile=.  -checks=-*,readability-function-size source.cpp | 
|  | $ # Note that there won't be timings table printed to the console. | 
|  | $ ls /tmp/out/ | 
|  | 20180516161318717446360-source.cpp.json | 
|  | $ cat 20180516161318717446360-source.cpp.json | 
|  | { | 
|  | "file": "/path/to/source.cpp", | 
|  | "timestamp": "2018-05-16 16:13:18.717446360", | 
|  | "profile": { | 
|  | "time.clang-tidy.readability-function-size.wall": 1.0421266555786133e+00, | 
|  | "time.clang-tidy.readability-function-size.user": 9.2088400000005421e-01, | 
|  | "time.clang-tidy.readability-function-size.sys": 1.2418899999999974e-01 | 
|  | } | 
|  | } | 
|  |  | 
|  | There is only one argument that controls profile storage: | 
|  |  | 
|  | * ``-store-check-profile=<prefix>`` | 
|  |  | 
|  | By default reports are printed in tabulated format to stderr. When this option | 
|  | is passed, these per-TU profiles are instead stored as JSON. | 
|  | If the prefix is not an absolute path, it is considered to be relative to the | 
|  | directory from where you have run :program:`clang-tidy`. All ``.`` and ``..`` | 
|  | patterns in the path are collapsed, and symlinks are resolved. | 
|  |  | 
|  | Example: | 
|  | Let's suppose you have a source file named ``example.cpp``, located in the | 
|  | ``/source`` directory. Only the input filename is used, not the full path | 
|  | to the source file. Additionally, it is prefixed with the current timestamp. | 
|  |  | 
|  | * If you specify ``-store-check-profile=/tmp``, then the profile will be saved | 
|  | to ``/tmp/<ISO8601-like timestamp>-example.cpp.json`` | 
|  |  | 
|  | * If you run :program:`clang-tidy` from within ``/foo`` directory, and specify | 
|  | ``-store-check-profile=.``, then the profile will still be saved to | 
|  | ``/foo/<ISO8601-like timestamp>-example.cpp.json`` |