Skip to content

Commit 9c4b4ab

Browse files
committed
Add documentation for clang-tidy plugin
Signed-off-by: Mike Crowe <[email protected]>
1 parent 9a607b6 commit 9c4b4ab

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed

docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ By default, implicit conversions are enabled.
2323

2424
You can prepare existing code by already defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` and replace any implicit
2525
conversions with calls to [`get`](../basic_json/get.md).
26+
The [clang-tidy modernize-nlohmann-json-explicit-conversions](../../integration/clang-tidy.md#modernize-nlohmann-json-explicit-conversions)
27+
check can help to do this automatically.
2628

2729
!!! hint "CMake option"
2830

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Clang-Tidy
2+
3+
The library comes with a [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) plugin.
4+
It is disabled by default but can be enabled by enabling the `JSON_ClangTidyPlugin` [CMake option](cmake.md#json_clangtidyplugin).
5+
Clang-tidy [Plugins](https://clang.llvm.org/extra/clang-tidy/ExternalClang-TidyExamples.html) are only supported by Clang 16 and later.
6+
7+
## Building the plugin
8+
9+
You will need to have the development files matching your version of clang-tidy installed to build the plugin.
10+
For example, if you are running on a Debian-derived Linux distribution:
11+
12+
```sh
13+
apt install clang-tidy libclang-dev
14+
```
15+
but if this installs a version that is older than Clang 16 then you might be able to specify a newer version. For example:
16+
```sh
17+
apt install clang-tidy-19 libclang-19-dev
18+
```
19+
20+
```sh
21+
mkdir build
22+
cd build
23+
cmake -DJSON_ClangTidyPlugin=ON ..
24+
cmake -build .
25+
```
26+
27+
# Running the plugin
28+
To tell clang-tidy to use the plugin you must pass a path to it as an argument to the `-load` option.
29+
For example, you can run clang-tidy with only the _modernize-nlohmann-json-explicit-conversion_ check using the plugin on a single file with:
30+
```sh
31+
clang-tidy -load .../path/to/build/clang_tidy_plugin/libNlohmannJsonClangTidyPlugin.so -checks='-*,modernize-nlohmann-json-explicit-conversions` -fix source.cpp
32+
clang-tidy
33+
```
34+
or you can create a `.clang-tidy` file to enable the checks you require.
35+
36+
# Checks
37+
38+
At the moment the plugin contains only a single check.
39+
40+
## modernize-nlohmann-json-explicit-conversions
41+
42+
This check converts code that takes advantage of [implicit conversions](../api/macros/json_use_implicit_conversions.md) to use explicit `get()` calls using the correct templated type.
43+
For example, it turns:
44+
```c++
45+
void f(const nlohmann::json &j1, const nlohmann::json &j2)
46+
{
47+
int i = j1;
48+
double d = j2.at("value");
49+
bool b = *j2.find("valid");
50+
std::cout << i << " " << d << " " << b << "\n";
51+
}
52+
```
53+
into
54+
```c++
55+
void f(const nlohmann::json &j1, const nlohmann::json &j2)
56+
{
57+
int i = j1.get<int>();
58+
double d = j2.at("value").get<double>();
59+
bool b = j2.find("valid")->get<bool>();
60+
std::cout << i << " " << d << " " << b << "\n";
61+
}
62+
```
63+
by knowing what the target type is for the implicit conversion and turning
64+
that into an explicit call to the `get()` method with that type as the
65+
template parameter.
66+
67+
Unfortunately the check does not work very well if the implicit conversion
68+
occurs in templated code or in a system header. For example, the following
69+
won't be fixed because the implicit conversion will happen inside
70+
`std::optional`'s constructor:
71+
```c++
72+
void f(const nlohmann::json &j)
73+
{
74+
std::optional<int> oi;
75+
const auto &it = j.find("value");
76+
if (it != j.end())
77+
oi = *it;
78+
// ...
79+
}
80+
```
81+
After you have run this check you can set [JSON_USE_IMPLICIT_CONVERSIONS=0](../api/macros/json_use_implicit_conversions.md) to find any occurrences that the check have not been fixed automatically.
82+
83+
### Limitations
84+
85+
#### Typedefs may leak platform specifics
86+
87+
The check sees through `typedef` which can cause types that ought to vary by platform to become fixed by the check. This is particularly a problem when using the fixed-sized types from `<cstdint>` or other platform-specific types like `size_t` and `off_t`. For example, converting:
88+
```c++
89+
uint64_t u64 = j.at("value");
90+
```
91+
in a 64-bit Linux environment will result in:
92+
```c++
93+
uint64_t u64 = j.at("value").get<unsigned long>();
94+
```
95+
but in a 32-bit Linux environment will result in:
96+
```c++
97+
uint64_t u64 = j.at("value").get<unsigned long long>();
98+
```
99+
100+
This could cause serious bugs. If you use such types in code you apply the check to it is recommended that you run on all your target platforms and compare the results.
101+
102+
Other more-benign uses of `typedef` types may also cause the resultant code to look uglier.
103+
104+
#### Redundant casts
105+
106+
Code using the library may use casts to force the correct type. Such code will be fixed but the unnecessary cast will remain, which could cause confusion and be brittle when the code is changed. For example, converting:
107+
```c++
108+
const auto value = static_cast<int>(j["value"])
109+
```
110+
will yield:
111+
```
112+
const auto value = static_cast<int>(j["value"].get<int>())
113+
```

docs/mkdocs/docs/integration/cmake.md

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/
131131

132132
Enable CI build targets. The exact targets are used during the several CI steps and are subject to change without notice. This option is `OFF` by default.
133133

134+
### `JSON_ClangTidyPlugin`
135+
136+
Enable building the [clang-tidy plugin](clang-tidy.md). This option is `OFF` by default.
137+
134138
### `JSON_Diagnostics`
135139

136140
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.

docs/mkdocs/mkdocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ nav:
9393
- Integration:
9494
- integration/index.md
9595
- integration/migration_guide.md
96+
- integration/clang-tidy.md
9697
- integration/cmake.md
9798
- integration/package_managers.md
9899
- integration/pkg-config.md

0 commit comments

Comments
 (0)