forked from OSchip/llvm-project
[Documentation] Add a chapter about Clang-tidy integrations.
Patch by Marina Kalashina. Differential Revision: https://reviews.llvm.org/D54945 llvm-svn: 351463
This commit is contained in:
parent
7ab15a79be
commit
fb877cb9f2
|
@ -0,0 +1,507 @@
|
|||
================
|
||||
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: http://clang.llvm.org/docs/LibASTMatchers.html
|
||||
.. _PPCallbacks: http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html
|
||||
.. _clang-check: http://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 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/tools/clang/tools/extra`` directory, and
|
||||
let's start!
|
||||
|
||||
.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html
|
||||
.. _Using Clang Tools: http://clang.llvm.org/docs/ClangTools.html
|
||||
|
||||
|
||||
The Directory Structure
|
||||
-----------------------
|
||||
|
||||
:program:`clang-tidy` source code resides in the
|
||||
``llvm/tools/clang/tools/extra`` directory and is structured as follows:
|
||||
|
||||
::
|
||||
|
||||
clang-tidy/ # Clang-tidy core.
|
||||
|-- ClangTidy.h # Interfaces for users and 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: http://llvm.org/docs/GettingStarted.html
|
||||
.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html
|
||||
.. _LLVM Phabricator: http://llvm.org/docs/Phabricator.html
|
||||
|
||||
Next, you need to decide which module the check belongs to. Modules
|
||||
are located in subdirectories of `clang-tidy/
|
||||
<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/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 "../ClangTidy.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
|
||||
<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.h>`_
|
||||
and `clang-tidy/google/ExplicitConstructorCheck.cpp
|
||||
<http://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: http://llvm.org/docs/CommandGuide/lit.html
|
||||
.. _FileCheck: http://llvm.org/docs/CommandGuide/FileCheck.html
|
||||
.. _test/clang-tidy/google-readability-casting.cpp: http://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 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.
|
||||
|
||||
* 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``
|
|
@ -0,0 +1,117 @@
|
|||
==================================
|
||||
Clang-tidy IDE/Editor Integrations
|
||||
==================================
|
||||
|
||||
.. _Clangd: https://clang.llvm.org/extra/clangd.html
|
||||
|
||||
Apart from being a standalone tool, :program:`clang-tidy` is integrated into
|
||||
various IDEs, code analyzers, and editors. Besides, it is currently being
|
||||
integrated into Clangd_. The following table shows the most
|
||||
well-known :program:`clang-tidy` integrations in detail.
|
||||
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
| | Feature |
|
||||
+======================================+========================+=================================+==========================+=========================================+==========================+
|
||||
| **Tool** | On-the-fly inspection | Check list configuration (GUI) | Options to checks (GUI) | Configuration via ``.clang-tidy`` files | Custom clang-tidy binary |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|A.L.E. for Vim | \+\ | \-\ | \-\ | \-\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Clang Power Tools for Visual Studio | \-\ | \+\ | \-\ | \+\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Clangd | \+\ | \-\ | \-\ | \-\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|CLion IDE | \+\ | \+\ | \+\ | \+\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|CodeChecker | \-\ | \-\ | \-\ | \-\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|CPPCheck | \-\ | \-\ | \-\ | \-\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|CPPDepend | \-\ | \-\ | \-\ | \-\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Flycheck for Emacs | \+\ | \-\ | \-\ | \+\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|KDevelop IDE | \-\ | \+\ | \+\ | \+\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Qt Creator IDE | \+\ | \+\ | \-\ | \-\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|ReSharper C++ for Visual Studio | \+\ | \+\ | \-\ | \+\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Syntastic for Vim | \+\ | \-\ | \-\ | \-\ | \+\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|Visual Assist for Visual Studio | \+\ | \+\ | \-\ | \-\ | \-\ |
|
||||
+--------------------------------------+------------------------+---------------------------------+--------------------------+-----------------------------------------+--------------------------+
|
||||
|
||||
**IDEs**
|
||||
|
||||
.. _CLion: https://www.jetbrains.com/clion/
|
||||
.. _integrates clang-tidy: https://www.jetbrains.com/help/clion/clang-tidy-checks-support.html
|
||||
|
||||
CLion_ 2017.2 and later `integrates clang-tidy`_ as an extension to the
|
||||
built-in code analyzer. Starting from 2018.2 EAP, CLion allows using
|
||||
:program:`clang-tidy` via Clangd. Inspections and applicable quick-fixes are
|
||||
performed on the fly, and checks can be configured in standard command line
|
||||
format. In this integration, you can switch to the :program:`clang-tidy`
|
||||
binary different from the bundled one, pass the configuration in
|
||||
``.clang-tidy`` files instead of using the IDE settings, and configure
|
||||
options for particular checks.
|
||||
|
||||
.. _KDevelop: https://www.kdevelop.org/
|
||||
.. _kdev-clang-tidy: https://github.com/KDE/kdev-clang-tidy/
|
||||
|
||||
KDevelop_ with the kdev-clang-tidy_ plugin, starting from version 5.1, performs
|
||||
static analysis using :program:`clang-tidy`. The plugin launches the
|
||||
:program:`clang-tidy` binary from the specified location and parses its
|
||||
output to provide a list of issues.
|
||||
|
||||
.. _QtCreator: https://www.qt.io/
|
||||
.. _Clang Code Model: http://doc.qt.io/qtcreator/creator-clang-codemodel.html
|
||||
|
||||
QtCreator_ 4.6 integrates :program:`clang-tidy` warnings into the editor
|
||||
diagnostics under the `Clang Code Model`_. To employ :program:`clang-tidy`
|
||||
inspection in QtCreator, you need to create a copy of one of the presets and
|
||||
choose the checks to be performed in the Clang Code Model Warnings menu.
|
||||
|
||||
.. _MS Visual Studio: https://visualstudio.microsoft.com/
|
||||
.. _ReSharper C++: https://www.jetbrains.com/help/resharper/Clang_Tidy_Integration.html
|
||||
.. _Visual Assist: https://docs.wholetomato.com/default.asp?W761
|
||||
.. _Clang Power Tools: https://marketplace.visualstudio.com/items?itemName=caphyon.ClangPowerTools
|
||||
.. _clang-tidy-vs: https://github.com/llvm-mirror/clang-tools-extra/tree/master/clang-tidy-vs
|
||||
|
||||
`MS Visual Studio`_ has a native clang-tidy-vs_ plugin and also can integrate
|
||||
:program:`clang-tidy` by means of three other tools. The `ReSharper C++`_
|
||||
extension, version 2017.3 and later, provides seamless :program:`clang-tidy`
|
||||
integration: checks and quick-fixes run alongside native inspections. Apart
|
||||
from that, ReSharper C++ incorporates :program:`clang-tidy` as a separate
|
||||
step of its code clean-up process. `Visual Assist`_ build 2210 includes a
|
||||
subset of :program:`clang-tidy` checklist to inspect the code as you edit.
|
||||
Another way to bring :program:`clang-tidy` functionality to Visual Studio is
|
||||
the `Clang Power Tools`_ plugin, which includes most of the
|
||||
:program:`clang-tidy` checks and runs them during compilation or as a separate
|
||||
step of code analysis.
|
||||
|
||||
**Editors**
|
||||
|
||||
.. _Flycheck: https://github.com/ch1bo/flycheck-clang-tidy
|
||||
.. _Syntastic: https://github.com/vim-syntastic/syntastic
|
||||
.. _A.L.E.: https://github.com/w0rp/ale
|
||||
.. _Emacs24: https://www.gnu.org/s/emacs/
|
||||
.. _Vim: https://www.vim.org/
|
||||
|
||||
Emacs24_, when expanded with the Flycheck_ plugin, incorporates the
|
||||
:program:`clang-tidy` inspection into the syntax analyzer. For Vim_, you can
|
||||
use Syntastic_, which includes :program:`clang-tidy`, or `A.L.E.`_,
|
||||
a lint engine that applies :program:`clang-tidy` along with other linters.
|
||||
|
||||
**Analyzers**
|
||||
|
||||
.. _CPPDepend: https://www.cppdepend.com/cppdependv2018
|
||||
.. _CPPCheck: https://sourceforge.net/p/cppcheck/news/
|
||||
.. _CodeChecker: https://github.com/Ericsson/codechecker
|
||||
.. _plugin: https://github.com/Ericsson/CodeCheckerEclipsePlugin
|
||||
|
||||
:program:`clang-tidy` is integrated in CPPDepend_ starting from version 2018.1
|
||||
and CPPCheck_ 1.82. CPPCheck integration lets you import Visual Studio
|
||||
solutions and run the :program:`clang-tidy` inspection on them. The
|
||||
CodeChecker_ application of version 5.3 or later, which also comes as a plugin_
|
||||
for Eclipse, supports :program:`clang-tidy` as a static analysis instrument and
|
||||
allows to use a custom :program:`clang-tidy` binary.
|
|
@ -10,6 +10,8 @@ See also:
|
|||
:maxdepth: 1
|
||||
|
||||
The list of clang-tidy checks <checks/list>
|
||||
Clang-tidy IDE/Editor Integrations <Integrations>
|
||||
Getting Involved <Contributing>
|
||||
|
||||
:program:`clang-tidy` is a clang-based C++ "linter" tool. Its purpose is to
|
||||
provide an extensible framework for diagnosing and fixing typical programming
|
||||
|
@ -310,511 +312,3 @@ the parenthesis) whitespaces can be used and will be ignored.
|
|||
|
||||
.. _LibTooling: http://clang.llvm.org/docs/LibTooling.html
|
||||
.. _How To Setup Tooling For LLVM: http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
|
||||
|
||||
|
||||
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: http://clang.llvm.org/docs/LibASTMatchers.html
|
||||
.. _PPCallbacks: http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html
|
||||
.. _clang-check: http://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 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/tools/clang/tools/extra`` directory, and
|
||||
let's start!
|
||||
|
||||
.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html
|
||||
.. _Using Clang Tools: http://clang.llvm.org/docs/ClangTools.html
|
||||
|
||||
|
||||
The Directory Structure
|
||||
-----------------------
|
||||
|
||||
:program:`clang-tidy` source code resides in the
|
||||
``llvm/tools/clang/tools/extra`` directory and is structured as follows:
|
||||
|
||||
::
|
||||
|
||||
clang-tidy/ # Clang-tidy core.
|
||||
|-- ClangTidy.h # Interfaces for users and 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: http://llvm.org/docs/GettingStarted.html
|
||||
.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html
|
||||
.. _LLVM Phabricator: http://llvm.org/docs/Phabricator.html
|
||||
|
||||
Next, you need to decide which module the check belongs to. Modules
|
||||
are located in subdirectories of `clang-tidy/
|
||||
<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/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 "../ClangTidy.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
|
||||
<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.h>`_
|
||||
and `clang-tidy/google/ExplicitConstructorCheck.cpp
|
||||
<http://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: http://llvm.org/docs/CommandGuide/lit.html
|
||||
.. _FileCheck: http://llvm.org/docs/CommandGuide/FileCheck.html
|
||||
.. _test/clang-tidy/google-readability-casting.cpp: http://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 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.
|
||||
|
||||
* 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``
|
||||
|
|
Loading…
Reference in New Issue