Author: Zeyi Xu Date: 2026-07-25T21:47:16+08:00 New Revision: 0252b421b1725c627ca00f3cee7663cb9882291a
URL: https://github.com/llvm/llvm-project/commit/0252b421b1725c627ca00f3cee7663cb9882291a DIFF: https://github.com/llvm/llvm-project/commit/0252b421b1725c627ca00f3cee7663cb9882291a.diff LOG: [clang-tidy][docs] Rewrite remaining abseil check docs to Markdown (#212004) This commit rewrites the reST documentation to Markdown. Tracking issue: #201242 See the [migration guide] for more information. [migration guide]: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines AI Usage: This was prepared with rst2myst and GPT5.6-assisted cleanup, I manually verified that all the documentations render as expected. Preview site for reviewing: https://broken.life/llvm-staging/abseil-markdown-port/ Added: Modified: clang-tools-extra/docs/clang-tidy/checks/abseil/duration-comparison.md clang-tools-extra/docs/clang-tidy/checks/abseil/duration-conversion-cast.md clang-tools-extra/docs/clang-tidy/checks/abseil/duration-division.md clang-tools-extra/docs/clang-tidy/checks/abseil/duration-factory-scale.md clang-tools-extra/docs/clang-tidy/checks/abseil/duration-subtraction.md clang-tools-extra/docs/clang-tidy/checks/abseil/duration-unnecessary-conversion.md clang-tools-extra/docs/clang-tidy/checks/abseil/faster-strsplit-delimiter.md clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.md clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-str-contains.md clang-tools-extra/docs/clang-tidy/checks/abseil/time-subtraction.md clang-tools-extra/docs/clang-tidy/checks/abseil/unchecked-statusor-access.md clang-tools-extra/docs/clang-tidy/checks/abseil/upgrade-duration-conversions.md Removed: ################################################################################ diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-comparison.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-comparison.md index 6df0514dec683..aab1f1d39d5f4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-comparison.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-comparison.md @@ -1,33 +1,33 @@ -.. title:: clang-tidy - abseil-duration-comparison +```{title} clang-tidy - abseil-duration-comparison +``` -abseil-duration-comparison -========================== +# abseil-duration-comparison -Checks for comparisons which should be in the ``absl::Duration`` domain instead +Checks for comparisons which should be in the `absl::Duration` domain instead of the floating point or integer domains. -N.B.: In cases where a ``Duration`` was being converted to an integer and then -compared against a floating-point value, truncation during the ``Duration`` +N.B.: In cases where a `Duration` was being converted to an integer and then +compared against a floating-point value, truncation during the `Duration` conversion might yield a diff erent result. In practice this is very rare, and still indicates a bug which should be fixed. Examples: -.. code-block:: c++ +```cpp +// Original - Comparison in the floating point domain +double x; +absl::Duration d; +if (x < absl::ToDoubleSeconds(d)) ... - // Original - Comparison in the floating point domain - double x; - absl::Duration d; - if (x < absl::ToDoubleSeconds(d)) ... +// Suggested - Compare in the absl::Duration domain instead +if (absl::Seconds(x) < d) ... - // Suggested - Compare in the absl::Duration domain instead - if (absl::Seconds(x) < d) ... +// Original - Comparison in the integer domain +int x; +absl::Duration d; +if (x < absl::ToInt64Microseconds(d)) ... - // Original - Comparison in the integer domain - int x; - absl::Duration d; - if (x < absl::ToInt64Microseconds(d)) ... - - // Suggested - Compare in the absl::Duration domain instead - if (absl::Microseconds(x) < d) ... +// Suggested - Compare in the absl::Duration domain instead +if (absl::Microseconds(x) < d) ... +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-conversion-cast.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-conversion-cast.md index 05c11cddfd5f9..0e647214f4e12 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-conversion-cast.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-conversion-cast.md @@ -1,31 +1,30 @@ -.. title:: clang-tidy - abseil-duration-conversion-cast +```{title} clang-tidy - abseil-duration-conversion-cast +``` -abseil-duration-conversion-cast -=============================== +# abseil-duration-conversion-cast -Checks for casts of ``absl::Duration`` conversion functions, and recommends +Checks for casts of `absl::Duration` conversion functions, and recommends the right conversion function instead. Examples: -.. code-block:: c++ +```cpp +// Original - Cast from a double to an integer +absl::Duration d; +int i = static_cast<int>(absl::ToDoubleSeconds(d)); - // Original - Cast from a double to an integer - absl::Duration d; - int i = static_cast<int>(absl::ToDoubleSeconds(d)); +// Suggested - Use the integer conversion function directly. +int i = absl::ToInt64Seconds(d); - // Suggested - Use the integer conversion function directly. - int i = absl::ToInt64Seconds(d); +// Original - Cast from a double to an integer +absl::Duration d; +double x = static_cast<double>(absl::ToInt64Seconds(d)); - // Original - Cast from a double to an integer - absl::Duration d; - double x = static_cast<double>(absl::ToInt64Seconds(d)); - - // Suggested - Use the integer conversion function directly. - double x = absl::ToDoubleSeconds(d); - +// Suggested - Use the integer conversion function directly. +double x = absl::ToDoubleSeconds(d); +``` Note: In the second example, the suggested fix could yield a diff erent result, as the conversion to integer could truncate. In practice, this is very rare, -and you should use ``absl::Trunc`` to perform this operation explicitly instead. +and you should use `absl::Trunc` to perform this operation explicitly instead. diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-division.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-division.md index 40c12d464687d..beb38bd63ef2b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-division.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-division.md @@ -1,38 +1,37 @@ -.. title:: clang-tidy - abseil-duration-division +```{title} clang-tidy - abseil-duration-division +``` -abseil-duration-division -======================== +# abseil-duration-division -``absl::Duration`` arithmetic works like it does with integers. That means that -division of two ``absl::Duration`` objects returns an ``int64`` with any +`absl::Duration` arithmetic works like it does with integers. That means that +division of two `absl::Duration` objects returns an `int64` with any fractional component truncated toward 0. -See `this link <https://github.com/abseil/abseil-cpp/blob/29ff6d4860070bf8fcbd39c8805d0c32d56628a3/absl/time/time.h#L137>`_ -for more information on arithmetic with ``absl::Duration``. +See [this link](https://github.com/abseil/abseil-cpp/blob/29ff6d4860070bf8fcbd39c8805d0c32d56628a3/absl/time/time.h#L137) +for more information on arithmetic with `absl::Duration`. For example: -.. code-block:: c++ +```cpp +absl::Duration d = absl::Seconds(3.5); +int64 sec1 = d / absl::Seconds(1); // Truncates toward 0. +int64 sec2 = absl::ToInt64Seconds(d); // Equivalent to division. +assert(sec1 == 3 && sec2 == 3); - absl::Duration d = absl::Seconds(3.5); - int64 sec1 = d / absl::Seconds(1); // Truncates toward 0. - int64 sec2 = absl::ToInt64Seconds(d); // Equivalent to division. - assert(sec1 == 3 && sec2 == 3); - - double dsec = d / absl::Seconds(1); // WRONG: Still truncates toward 0. - assert(dsec == 3.0); +double dsec = d / absl::Seconds(1); // WRONG: Still truncates toward 0. +assert(dsec == 3.0); +``` If you want floating-point division, you should use either the -``absl::FDivDuration()`` function, or one of the unit conversion functions such -as ``absl::ToDoubleSeconds()``. For example: - -.. code-block:: c++ - - absl::Duration d = absl::Seconds(3.5); - double dsec1 = absl::FDivDuration(d, absl::Seconds(1)); // GOOD: No truncation. - double dsec2 = absl::ToDoubleSeconds(d); // GOOD: No truncation. - assert(dsec1 == 3.5 && dsec2 == 3.5); +`absl::FDivDuration()` function, or one of the unit conversion functions such +as `absl::ToDoubleSeconds()`. For example: +```cpp +absl::Duration d = absl::Seconds(3.5); +double dsec1 = absl::FDivDuration(d, absl::Seconds(1)); // GOOD: No truncation. +double dsec2 = absl::ToDoubleSeconds(d); // GOOD: No truncation. +assert(dsec1 == 3.5 && dsec2 == 3.5); +``` -This check looks for uses of ``absl::Duration`` division that is done in a +This check looks for uses of `absl::Duration` division that is done in a floating-point context, and recommends the use of a function that returns a floating-point value. diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-factory-scale.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-factory-scale.md index cba5202957463..a2e73c2bb9616 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-factory-scale.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-factory-scale.md @@ -1,35 +1,35 @@ -.. title:: clang-tidy - abseil-duration-factory-scale +```{title} clang-tidy - abseil-duration-factory-scale +``` -abseil-duration-factory-scale -============================= +# abseil-duration-factory-scale -Checks for cases where arguments to ``absl::Duration`` factory functions are +Checks for cases where arguments to `absl::Duration` factory functions are scaled internally and could be changed to a diff erent factory function. This check also looks for arguments with a zero value and suggests using -``absl::ZeroDuration()`` instead. +`absl::ZeroDuration()` instead. Examples: -.. code-block:: c++ +```cpp +// Original - Internal multiplication. +int x; +absl::Duration d = absl::Seconds(60 * x); - // Original - Internal multiplication. - int x; - absl::Duration d = absl::Seconds(60 * x); +// Suggested - Use absl::Minutes instead. +absl::Duration d = absl::Minutes(x); - // Suggested - Use absl::Minutes instead. - absl::Duration d = absl::Minutes(x); +// Original - Internal division. +int y; +absl::Duration d = absl::Milliseconds(y / 1000.); - // Original - Internal division. - int y; - absl::Duration d = absl::Milliseconds(y / 1000.); +// Suggested - Use absl:::Seconds instead. +absl::Duration d = absl::Seconds(y); - // Suggested - Use absl:::Seconds instead. - absl::Duration d = absl::Seconds(y); +// Original - Zero-value argument. +absl::Duration d = absl::Hours(0); - // Original - Zero-value argument. - absl::Duration d = absl::Hours(0); - - // Suggested = Use absl::ZeroDuration instead - absl::Duration d = absl::ZeroDuration(); +// Suggested = Use absl::ZeroDuration instead +absl::Duration d = absl::ZeroDuration(); +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-subtraction.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-subtraction.md index 3dfd326562084..3032a9118ace7 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-subtraction.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-subtraction.md @@ -1,36 +1,35 @@ -.. title:: clang-tidy - abseil-duration-subtraction +```{title} clang-tidy - abseil-duration-subtraction +``` -abseil-duration-subtraction -=========================== +# abseil-duration-subtraction Checks for cases where subtraction should be performed in the -``absl::Duration`` domain. When subtracting two values, and the first one is -known to be a conversion from ``absl::Duration``, we can infer that the second -should also be interpreted as an ``absl::Duration``, and make that inference +`absl::Duration` domain. When subtracting two values, and the first one is +known to be a conversion from `absl::Duration`, we can infer that the second +should also be interpreted as an `absl::Duration`, and make that inference explicit. Examples: -.. code-block:: c++ +```cpp +// Original - Subtraction in the double domain +double x; +absl::Duration d; +double result = absl::ToDoubleSeconds(d) - x; - // Original - Subtraction in the double domain - double x; - absl::Duration d; - double result = absl::ToDoubleSeconds(d) - x; +// Suggestion - Subtraction in the absl::Duration domain instead +double result = absl::ToDoubleSeconds(d - absl::Seconds(x)); - // Suggestion - Subtraction in the absl::Duration domain instead - double result = absl::ToDoubleSeconds(d - absl::Seconds(x)); +// Original - Subtraction of two Durations in the double domain +absl::Duration d1, d2; +double result = absl::ToDoubleSeconds(d1) - absl::ToDoubleSeconds(d2); - // Original - Subtraction of two Durations in the double domain - absl::Duration d1, d2; - double result = absl::ToDoubleSeconds(d1) - absl::ToDoubleSeconds(d2); +// Suggestion - Subtraction in the absl::Duration domain instead +double result = absl::ToDoubleSeconds(d1 - d2); +``` - // Suggestion - Subtraction in the absl::Duration domain instead - double result = absl::ToDoubleSeconds(d1 - d2); - - -Note: As with other ``clang-tidy`` checks, it is possible that multiple fixes +Note: As with other `clang-tidy` checks, it is possible that multiple fixes may overlap (as in the case of nested expressions), so not all occurrences can be transformed in one run. In particular, this may occur for nested subtraction -expressions. Running ``clang-tidy`` multiple times will find and fix these +expressions. Running `clang-tidy` multiple times will find and fix these overlaps. diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-unnecessary-conversion.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-unnecessary-conversion.md index 264c5d08b9d29..2d564550ebab5 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-unnecessary-conversion.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/duration-unnecessary-conversion.md @@ -1,57 +1,57 @@ -.. title:: clang-tidy - abseil-duration-unnecessary-conversion +```{title} clang-tidy - abseil-duration-unnecessary-conversion +``` -abseil-duration-unnecessary-conversion -====================================== +# abseil-duration-unnecessary-conversion -Finds and fixes cases where ``absl::Duration`` values are being converted to +Finds and fixes cases where `absl::Duration` values are being converted to numeric types and back again. Floating-point examples: -.. code-block:: c++ +```cpp +// Original - Conversion to double and back again +absl::Duration d1; +absl::Duration d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); - // Original - Conversion to double and back again - absl::Duration d1; - absl::Duration d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); +// Suggestion - Remove unnecessary conversions +absl::Duration d2 = d1; - // Suggestion - Remove unnecessary conversions - absl::Duration d2 = d1; +// Original - Division to convert to double and back again +absl::Duration d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(1))); - // Original - Division to convert to double and back again - absl::Duration d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(1))); - - // Suggestion - Remove division and conversion - absl::Duration d2 = d1; +// Suggestion - Remove division and conversion +absl::Duration d2 = d1; +``` Integer examples: -.. code-block:: c++ - - // Original - Conversion to integer and back again - absl::Duration d1; - absl::Duration d2 = absl::Hours(absl::ToInt64Hours(d1)); +```cpp +// Original - Conversion to integer and back again +absl::Duration d1; +absl::Duration d2 = absl::Hours(absl::ToInt64Hours(d1)); - // Suggestion - Remove unnecessary conversions - absl::Duration d2 = d1; +// Suggestion - Remove unnecessary conversions +absl::Duration d2 = d1; - // Original - Integer division followed by conversion - absl::Duration d2 = absl::Seconds(d1 / absl::Seconds(1)); +// Original - Integer division followed by conversion +absl::Duration d2 = absl::Seconds(d1 / absl::Seconds(1)); - // Suggestion - Remove division and conversion - absl::Duration d2 = d1; +// Suggestion - Remove division and conversion +absl::Duration d2 = d1; +``` Unwrapping scalar operations: -.. code-block:: c++ - - // Original - Multiplication by a scalar - absl::Duration d1; - absl::Duration d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2); +```cpp +// Original - Multiplication by a scalar +absl::Duration d1; +absl::Duration d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2); - // Suggestion - Remove unnecessary conversion - absl::Duration d2 = d1 * 2; +// Suggestion - Remove unnecessary conversion +absl::Duration d2 = d1 * 2; +``` -Note: Converting to an integer and back to an ``absl::Duration`` might be a +Note: Converting to an integer and back to an `absl::Duration` might be a truncating operation if the value is not aligned to the scale of conversion. In the rare case where this is the intended result, callers should use -``absl::Trunc`` to truncate explicitly. +`absl::Trunc` to truncate explicitly. diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/faster-strsplit-delimiter.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/faster-strsplit-delimiter.md index b5b79d405bded..b870ca9a79b00 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/faster-strsplit-delimiter.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/faster-strsplit-delimiter.md @@ -1,12 +1,12 @@ -.. title:: clang-tidy - abseil-faster-strsplit-delimiter +```{title} clang-tidy - abseil-faster-strsplit-delimiter +``` -abseil-faster-strsplit-delimiter -================================ +# abseil-faster-strsplit-delimiter -Finds instances of ``absl::StrSplit()`` or ``absl::MaxSplits()`` where the +Finds instances of `absl::StrSplit()` or `absl::MaxSplits()` where the delimiter is a single character string literal and replaces with a character. The check will offer a suggestion to change the string literal into a -character. It will also catch code using ``absl::ByAnyChar()`` for just a +character. It will also catch code using `absl::ByAnyChar()` for just a single character and will transform that into a single character as well. These changes will give the same result, but using characters rather than @@ -14,28 +14,28 @@ single character string literals is more efficient and readable. Examples: -.. code-block:: c++ +```cpp +// Original - the argument is a string literal. +for (auto piece : absl::StrSplit(str, "B")) { - // Original - the argument is a string literal. - for (auto piece : absl::StrSplit(str, "B")) { +// Suggested - the argument is a character, which causes the more efficient +// overload of absl::StrSplit() to be used. +for (auto piece : absl::StrSplit(str, 'B')) { - // Suggested - the argument is a character, which causes the more efficient - // overload of absl::StrSplit() to be used. - for (auto piece : absl::StrSplit(str, 'B')) { +// Original - the argument is a string literal inside absl::ByAnyChar call. +for (auto piece : absl::StrSplit(str, absl::ByAnyChar("B"))) { - // Original - the argument is a string literal inside absl::ByAnyChar call. - for (auto piece : absl::StrSplit(str, absl::ByAnyChar("B"))) { +// Suggested - the argument is a character, which causes the more efficient +// overload of absl::StrSplit() to be used and we do not need absl::ByAnyChar +// anymore. +for (auto piece : absl::StrSplit(str, 'B')) { - // Suggested - the argument is a character, which causes the more efficient - // overload of absl::StrSplit() to be used and we do not need absl::ByAnyChar - // anymore. - for (auto piece : absl::StrSplit(str, 'B')) { +// Original - the argument is a string literal inside absl::MaxSplits call. +for (auto piece : absl::StrSplit(str, absl::MaxSplits("B", 1))) { - // Original - the argument is a string literal inside absl::MaxSplits call. - for (auto piece : absl::StrSplit(str, absl::MaxSplits("B", 1))) { - - // Suggested - the argument is a character, which causes the more efficient - // overload of absl::StrSplit() to be used. - for (auto piece : absl::StrSplit(str, absl::MaxSplits('B', 1))) { +// Suggested - the argument is a character, which causes the more efficient +// overload of absl::StrSplit() to be used. +for (auto piece : absl::StrSplit(str, absl::MaxSplits('B', 1))) { +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.md index 41a7ab500d7ce..dcc398da8371e 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.md @@ -1,48 +1,48 @@ -.. title:: clang-tidy - abseil-string-find-startswith +```{title} clang-tidy - abseil-string-find-startswith +``` -abseil-string-find-startswith -============================= +# abseil-string-find-startswith -Checks whether a ``std::string::find()`` or ``std::string::rfind()`` (and -corresponding ``std::string_view`` methods) result is compared with 0, and -suggests replacing with ``absl::StartsWith()``. This is both a readability and +Checks whether a `std::string::find()` or `std::string::rfind()` (and +corresponding `std::string_view` methods) result is compared with 0, and +suggests replacing with `absl::StartsWith()`. This is both a readability and performance issue. -``starts_with`` was added as a built-in function on those types in C++20. If -available, prefer enabling :doc:`modernize-use-starts-ends-with +`starts_with` was added as a built-in function on those types in C++20. If +available, prefer enabling {doc}`modernize-use-starts-ends-with <../modernize/use-starts-ends-with>` instead of this check. -.. code-block:: c++ - - string s = "..."; - if (s.find("Hello World") == 0) { /* do something */ } - if (s.rfind("Hello World", 0) == 0) { /* do something */ } +```cpp +string s = "..."; +if (s.find("Hello World") == 0) { /* do something */ } +if (s.rfind("Hello World", 0) == 0) { /* do something */ } +``` becomes +```cpp +string s = "..."; +if (absl::StartsWith(s, "Hello World")) { /* do something */ } +if (absl::StartsWith(s, "Hello World")) { /* do something */ } +``` -.. code-block:: c++ - - string s = "..."; - if (absl::StartsWith(s, "Hello World")) { /* do something */ } - if (absl::StartsWith(s, "Hello World")) { /* do something */ } - - -Options -------- +## Options -.. option:: StringLikeClasses +```{option} StringLikeClasses - Semicolon-separated list of names of string-like classes. By default both - ``std::basic_string`` and ``std::basic_string_view`` are considered. The list - of methods to be considered is fixed. +Semicolon-separated list of names of string-like classes. By default both +`std::basic_string` and `std::basic_string_view` are considered. The list +of methods to be considered is fixed. +``` -.. option:: IncludeStyle +```{option} IncludeStyle - A string specifying which include-style is used, `llvm` or `google`. Default - is `llvm`. +A string specifying which include-style is used, `llvm` or `google`. Default +is `llvm`. +``` -.. option:: AbseilStringsMatchHeader +```{option} AbseilStringsMatchHeader - The location of Abseil's ``strings/match.h``. Defaults to - ``absl/strings/match.h``. +The location of Abseil's `strings/match.h`. Defaults to +`absl/strings/match.h`. +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-str-contains.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-str-contains.md index 418df193d6e0d..0d0ae252cf7a7 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-str-contains.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-str-contains.md @@ -1,52 +1,53 @@ -.. title:: clang-tidy - abseil-string-find-str-contains +```{title} clang-tidy - abseil-string-find-str-contains +``` -abseil-string-find-str-contains -=============================== +# abseil-string-find-str-contains -Finds ``s.find(...) == string::npos`` comparisons (for various string-like -types) and suggests replacing with ``absl::StrContains()``. +Finds `s.find(...) == string::npos` comparisons (for various string-like +types) and suggests replacing with `absl::StrContains()`. This improves readability and reduces the likelihood of accidentally mixing -``find()`` and ``npos`` from diff erent string-like types. +`find()` and `npos` from diff erent string-like types. -By default, "string-like types" includes ``::std::basic_string``, -``::std::basic_string_view``, and ``::absl::string_view``. See the +By default, "string-like types" includes `::std::basic_string`, +`::std::basic_string_view`, and `::absl::string_view`. See the StringLikeClasses option to change this. -.. code-block:: c++ +```cpp +std::string s = "..."; +if (s.find("Hello World") == std::string::npos) { /* do something */ } - std::string s = "..."; - if (s.find("Hello World") == std::string::npos) { /* do something */ } - - absl::string_view a = "..."; - if (absl::string_view::npos != a.find("Hello World")) { /* do something */ } +absl::string_view a = "..."; +if (absl::string_view::npos != a.find("Hello World")) { /* do something */ } +``` becomes -.. code-block:: c++ - - std::string s = "..."; - if (!absl::StrContains(s, "Hello World")) { /* do something */ } - - absl::string_view a = "..."; - if (absl::StrContains(a, "Hello World")) { /* do something */ } +```cpp +std::string s = "..."; +if (!absl::StrContains(s, "Hello World")) { /* do something */ } +absl::string_view a = "..."; +if (absl::StrContains(a, "Hello World")) { /* do something */ } +``` -Options -------- +## Options -.. option:: StringLikeClasses +```{option} StringLikeClasses - Semicolon-separated list of names of string-like classes. By default includes - ``::std::basic_string``, ``::std::basic_string_view``, and - ``::absl::string_view``. +Semicolon-separated list of names of string-like classes. By default includes +`::std::basic_string`, `::std::basic_string_view`, and +`::absl::string_view`. +``` -.. option:: IncludeStyle +```{option} IncludeStyle - A string specifying which include-style is used, `llvm` or `google`. Default - is `llvm`. +A string specifying which include-style is used, `llvm` or `google`. Default +is `llvm`. +``` -.. option:: AbseilStringsMatchHeader +```{option} AbseilStringsMatchHeader - The location of Abseil's ``strings/match.h``. Defaults to - ``absl/strings/match.h``. +The location of Abseil's `strings/match.h`. Defaults to +`absl/strings/match.h`. +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/time-subtraction.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/time-subtraction.md index c717ed389216a..5ff393e0250e8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/time-subtraction.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/time-subtraction.md @@ -1,39 +1,39 @@ -.. title:: clang-tidy - abseil-time-subtraction +```{title} clang-tidy - abseil-time-subtraction +``` -abseil-time-subtraction -======================= +# abseil-time-subtraction -Finds and fixes ``absl::Time`` subtraction expressions to do subtraction +Finds and fixes `absl::Time` subtraction expressions to do subtraction in the Time domain instead of the numeric domain. There are two cases of Time subtraction in which deduce additional type information: -- When the result is an ``absl::Duration`` and the first argument is an - ``absl::Time``. -- When the second argument is a ``absl::Time``. +- When the result is an `absl::Duration` and the first argument is an + `absl::Time`. +- When the second argument is a `absl::Time`. In the first case, we must know the result of the operation, since without that -the second operand could be either an ``absl::Time`` or an ``absl::Duration``. -In the second case, the first operand *must* be an ``absl::Time``, because -subtracting an ``absl::Time`` from an ``absl::Duration`` is not defined. +the second operand could be either an `absl::Time` or an `absl::Duration`. +In the second case, the first operand *must* be an `absl::Time`, because +subtracting an `absl::Time` from an `absl::Duration` is not defined. Examples: -.. code-block:: c++ +```cpp +int x; +absl::Time t; - int x; - absl::Time t; +// Original - absl::Duration result and first operand is an absl::Time. +absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x); - // Original - absl::Duration result and first operand is an absl::Time. - absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x); +// Suggestion - Perform subtraction in the Time domain instead. +absl::Duration d = t - absl::FromUnixSeconds(x); - // Suggestion - Perform subtraction in the Time domain instead. - absl::Duration d = t - absl::FromUnixSeconds(x); +// Original - Second operand is an absl::Time. +int i = x - absl::ToUnixSeconds(t); - // Original - Second operand is an absl::Time. - int i = x - absl::ToUnixSeconds(t); - - // Suggestion - Perform subtraction in the Time domain instead. - int i = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); +// Suggestion - Perform subtraction in the Time domain instead. +int i = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); +``` diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/unchecked-statusor-access.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/unchecked-statusor-access.md index c56ff8c886e2c..b8363edde7ea9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/unchecked-statusor-access.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/unchecked-statusor-access.md @@ -1,34 +1,33 @@ -.. title:: clang-tidy - abseil-unchecked-statusor-access +```{title} clang-tidy - abseil-unchecked-statusor-access +``` -abseil-unchecked-statusor-access -================================ +# abseil-unchecked-statusor-access This check identifies unsafe accesses to values contained in -``absl::StatusOr<T>`` objects. Below we will refer to this type as -``StatusOr<T>``. +`absl::StatusOr<T>` objects. Below we will refer to this type as +`StatusOr<T>`. -An access to the value of an ``StatusOr<T>`` occurs when one of its -``value``, ``operator*``, or ``operator->`` member functions is invoked. +An access to the value of an `StatusOr<T>` occurs when one of its +`value`, `operator*`, or `operator->` member functions is invoked. To align with common misconceptions, the check considers these member functions as equivalent, even though there are subtle diff erences related to exceptions vs. undefined behavior. -An access to the value of a ``StatusOr<T>`` is considered safe if and +An access to the value of a `StatusOr<T>` is considered safe if and only if code in the local scope (e.g. function body) ensures that the -status of the ``StatusOr<T>`` is ok in all possible execution paths that +status of the `StatusOr<T>` is ok in all possible execution paths that can reach the access. That should happen either through an explicit -check, using the ``StatusOr<T>::ok`` member function, or by constructing -the ``StatusOr<T>`` in a way that shows that its status is unambiguously +check, using the `StatusOr<T>::ok` member function, or by constructing +the `StatusOr<T>` in a way that shows that its status is unambiguously ok (e.g. by passing a value to its constructor). -Below we list some examples of safe and unsafe ``StatusOr<T>`` access +Below we list some examples of safe and unsafe `StatusOr<T>` access patterns. Note: If the check isn't behaving as you would have expected on a code -snippet, please `report it <http://github.com/llvm/llvm-project/issues/new>`__. +snippet, please [report it](http://github.com/llvm/llvm-project/issues/new). -False negatives ---------------- +## False negatives This check generally does **not** generate false negatives. That means that if an access is not marked as unsafe, it is provably safe. If it cannot prove an @@ -40,403 +39,388 @@ produce false positive reports. That being said, there are some heuristics used that in very rare cases might be incorrect: -- `a const method accessor (without arguments) that returns diff erent - values when called multiple times <#functionstability>`__. +- [a const method accessor (without arguments) that returns diff erent + values when called multiple times](#functionstability). -If you think the check generated a false negative, please `report -it <http://github.com/llvm/llvm-project/issues/new>`__. +If you think the check generated a false negative, please [report +it](http://github.com/llvm/llvm-project/issues/new). -Known limitations ------------------ +## Known limitations This is a non-exhaustive list of constructs that are currently not modelled in the check and will lead to false positives: -- `Checking a StatusOr and then capturing it in a lambda <#lambdas>`__ -- `Indexing into a container with the same index <#containers>`__ -- `Project specific helper-functions <#uncommonapi>`__, -- `Functions with a stable return value <#functionstability>`__ -- **Any** `cross-function reasoning <#crossfunction>`__. This is by - design and will not change in the future. +- [Checking a StatusOr and then capturing it in a lambda](#lambdas) +- [Indexing into a container with the same index](#containers) +- [Project specific helper-functions](#uncommonapi), +- [Functions with a stable return value](#functionstability) +- **Any** [cross-function reasoning](#crossfunction). This is by + design and will not change in the future. -Checking if the status is ok, then accessing the value ------------------------------------------------------- +## Checking if the status is ok, then accessing the value The check recognizes all straightforward ways for checking the status -and accessing the value contained in a ``StatusOr<T>`` object. For +and accessing the value contained in a `StatusOr<T>` object. For example: -.. code:: cpp +```cpp +void f(absl::StatusOr<int> x) { + if (x.ok()) { + use(*x); + } +} +``` - void f(absl::StatusOr<int> x) { - if (x.ok()) { - use(*x); - } - } - -Checking if the status is ok, then accessing the value from a copy ------------------------------------------------------------------- +## Checking if the status is ok, then accessing the value from a copy The criteria that the check uses is semantic, not syntactic. It -recognizes when a copy of the ``StatusOr<T>`` object being accessed is +recognizes when a copy of the `StatusOr<T>` object being accessed is known to have ok status. For example: -.. code:: cpp - - void f(absl::StatusOr<int> x1) { - if (x1.ok()) { - absl::optional<int> x2 = x1; - use(*x2); - } - } +```cpp +void f(absl::StatusOr<int> x1) { + if (x1.ok()) { + absl::optional<int> x2 = x1; + use(*x2); + } +} +``` -Ensuring that the status is ok using common macros --------------------------------------------------- +## Ensuring that the status is ok using common macros -The check is aware of common macros like ``ABSL_CHECK`` or ``ABSL_CHECK_OK``. -Those can be used to ensure that the status of a ``StatusOr<T>`` object +The check is aware of common macros like `ABSL_CHECK` or `ABSL_CHECK_OK`. +Those can be used to ensure that the status of a `StatusOr<T>` object is ok. For example: -.. code:: cpp +```cpp +void f(absl::StatusOr<int> x) { + ABSL_CHECK_OK(x); + use(*x); +} +``` - void f(absl::StatusOr<int> x) { - ABSL_CHECK_OK(x); - use(*x); - } +## Ensuring that the status is ok using googletest macros -Ensuring that the status is ok using googletest macros ------------------------------------------------------- - -The check is aware of ``googletest`` (or ``gtest``) macros and matchers. -Accessing the value of a ``StatusOr<T>`` object is considered safe if it -is preceded by an ``ASSERT_`` macro that ensures the status is ok. +The check is aware of `googletest` (or `gtest`) macros and matchers. +Accessing the value of a `StatusOr<T>` object is considered safe if it +is preceded by an `ASSERT_` macro that ensures the status is ok. For example: -.. code:: cpp - - TEST(MySuite, MyTest) { - absl::StatusOr<int> x = foo(); - ASSERT_OK(x); - use(*x); - } +```cpp +TEST(MySuite, MyTest) { + absl::StatusOr<int> x = foo(); + ASSERT_OK(x); + use(*x); +} - TEST(MySuite, MyOtherTest) { - absl::StatusOr<int> x = foo(); - ASSERT_THAT(x, absl_testing::IsOk()); - use(*x); - } +TEST(MySuite, MyOtherTest) { + absl::StatusOr<int> x = foo(); + ASSERT_THAT(x, absl_testing::IsOk()); + use(*x); +} +``` -The following ``googletest`` macros are supported: +The following `googletest` macros are supported: -- ``ASSERT_OK(...)`` -- ``ASSERT_TRUE(...)`` -- ``ASSERT_FALSE(...)`` -- ``ASSERT_THAT(...)`` +- `ASSERT_OK(...)` +- `ASSERT_TRUE(...)` +- `ASSERT_FALSE(...)` +- `ASSERT_THAT(...)` The following matchers are supported: -- ``IsOk()`` -- ``StatusIs(...)`` -- ``IsOkAndHolds(...)`` -- ``CanonicalStatusIs(...)`` +- `IsOk()` +- `StatusIs(...)` +- `IsOkAndHolds(...)` +- `CanonicalStatusIs(...)` -**Note**: ``EXPECT_`` macros (like ``EXPECT_OK`` or ``EXPECT_TRUE(x.ok())``) +**Note**: `EXPECT_` macros (like `EXPECT_OK` or `EXPECT_TRUE(x.ok())`) do **not** make subsequent accesses safe because they do not terminate the test execution. -Ensuring that the status is ok, then accessing the value in a correlated branch -------------------------------------------------------------------------------- +## Ensuring that the status is ok, then accessing the value in a correlated branch The check is aware of correlated branches in the code and can figure out -when a ``StatusOr<T>`` object is ensured to have ok status on all +when a `StatusOr<T>` object is ensured to have ok status on all execution paths that lead to an access. For example: -.. code:: cpp - - void f(absl::StatusOr<int> x) { - bool safe = false; - if (x.ok() && SomeOtherCondition()) { - safe = true; - } - // ... more code... - if (safe) { - use(*x); - } - } - -Accessing the value without checking the status ------------------------------------------------ +```cpp +void f(absl::StatusOr<int> x) { + bool safe = false; + if (x.ok() && SomeOtherCondition()) { + safe = true; + } + // ... more code... + if (safe) { + use(*x); + } +} +``` + +## Accessing the value without checking the status The check flags accesses to the value that are not locally guarded by a status check: -.. code:: cpp - - void f1(absl::StatusOr<int> x) { - use(*x); // unsafe: it is unclear whether the status of `x` is ok. - } +```cpp +void f1(absl::StatusOr<int> x) { + use(*x); // unsafe: it is unclear whether the status of `x` is ok. +} - void f2(absl::StatusOr<MyStruct> x) { - use(x->member); // unsafe: it is unclear whether the status of `x` is ok. - } +void f2(absl::StatusOr<MyStruct> x) { + use(x->member); // unsafe: it is unclear whether the status of `x` is ok. +} - void f3(absl::StatusOr<int> x) { - use(x.value()); // unsafe: it is unclear whether the status of `x` is ok. - } +void f3(absl::StatusOr<int> x) { + use(x.value()); // unsafe: it is unclear whether the status of `x` is ok. +} +``` -Use ``ABSL_CHECK_OK`` to signal that you knowingly want to crash on +Use `ABSL_CHECK_OK` to signal that you knowingly want to crash on non-OK values. -NOTE: Even though using ``.value()`` on a non-``ok()`` ``StatusOr`` is defined +NOTE: Even though using `.value()` on a non-`ok()` `StatusOr` is defined to crash, it is often unintentional. That is why our checker flags those as well. -Accessing the value in the wrong branch ---------------------------------------- +## Accessing the value in the wrong branch -The check is aware of the state of a ``StatusOr<T>`` object in diff erent +The check is aware of the state of a `StatusOr<T>` object in diff erent branches of the code. For example: -.. code:: cpp +```cpp +void f(absl::StatusOr<int> x) { + if (x.ok()) { + } else { + use(*x); // unsafe: it is clear that the status of `x` is *not* ok. + } +} +``` - void f(absl::StatusOr<int> x) { - if (x.ok()) { - } else { - use(*x); // unsafe: it is clear that the status of `x` is *not* ok. - } - } +(functionstability)= -.. _functionstability: - -Assuming a function result to be stable ---------------------------------------- +## Assuming a function result to be stable The check is aware that function results might not be stable. That is, consecutive calls to the same function might return diff erent values. For example: -.. code:: cpp - - void f(Foo foo) { - if (foo.x().ok()) { - use(*foo.x()); // unsafe: it is unclear whether the status of `foo.x()` is ok. - } - } +```cpp +void f(Foo foo) { + if (foo.x().ok()) { + use(*foo.x()); // unsafe: it is unclear whether the status of `foo.x()` is ok. + } +} +``` In such cases it is best to store the result of the function call in a local variable and use it to access the value. For example: -.. code:: cpp - - void f(Foo foo) { - if (const auto& x = foo.x(); x.ok()) { - use(*x); - } - } +```cpp +void f(Foo foo) { + if (const auto& x = foo.x(); x.ok()) { + use(*x); + } +} +``` -The check **does** assume that ``const``-qualified accessor functions +The check **does** assume that `const`-qualified accessor functions return a stable value if no non-const function was called between the two calls: -.. code:: cpp - - class Foo { - const absl::StatusOr<int>& get() const { - [...]; - } - } - void f(Foo foo) { - if (foo.get().ok()) { - use(*foo.get()); - } - } - -If there is a call to a non-``const``-qualified function, the check +```cpp +class Foo { + const absl::StatusOr<int>& get() const { + [...]; + } +} +void f(Foo foo) { + if (foo.get().ok()) { + use(*foo.get()); + } +} +``` + +If there is a call to a non-`const`-qualified function, the check assumes the return value of the accessor was mutated. -.. code:: cpp - - class Foo { - const absl::StatusOr<int>& get() const { - [...]; - } - void mutate(); - } - void f(Foo foo) { - if (foo.get().ok()) { - foo.mutate(); - use(*foo.get()); // unsafe: `mutate()` might have changed the state of the object - } - } - -.. _uncommonapi: - -Relying on invariants of uncommon APIs --------------------------------------- +```cpp +class Foo { + const absl::StatusOr<int>& get() const { + [...]; + } + void mutate(); +} +void f(Foo foo) { + if (foo.get().ok()) { + foo.mutate(); + use(*foo.get()); // unsafe: `mutate()` might have changed the state of the object + } +} +``` + +(uncommonapi)= + +## Relying on invariants of uncommon APIs The check is unaware of invariants of uncommon APIs. For example: -.. code:: cpp - - void f(Foo foo) { - if (foo.HasProperty("bar")) { - use(*foo.GetProperty("bar")); // unsafe: it is unclear whether the status of `foo.GetProperty("bar")` is ok. - } - } +```cpp +void f(Foo foo) { + if (foo.HasProperty("bar")) { + use(*foo.GetProperty("bar")); // unsafe: it is unclear whether the status of `foo.GetProperty("bar")` is ok. + } +} +``` In such cases it is best to check explicitly that the status of the -``StatusOr<T>`` object is ok. For example: - -.. code:: cpp +`StatusOr<T>` object is ok. For example: - void f(Foo foo) { - if (const auto& property = foo.GetProperty("bar"); property.ok()) { - use(*property); - } - } +```cpp +void f(Foo foo) { + if (const auto& property = foo.GetProperty("bar"); property.ok()) { + use(*property); + } +} +``` -.. _crossfunction: +(crossfunction)= -Checking if the ``StatusOr<T>`` is ok, then passing it to another function --------------------------------------------------------------------------- +## Checking if the `StatusOr<T>` is ok, then passing it to another function The check relies on local reasoning. The check and value access must both happen in the same function. An access is considered unsafe even if the caller of the function performing the access ensures that the status -of the ``StatusOr<T>`` is ok. For example: +of the `StatusOr<T>` is ok. For example: -.. code:: cpp +```cpp +void g(absl::StatusOr<int> x) { + use(*x); // unsafe: it is unclear whether the status of `x` is ok. +} - void g(absl::StatusOr<int> x) { - use(*x); // unsafe: it is unclear whether the status of `x` is ok. - } - - void f(absl::StatusOr<int> x) { - if (x.ok()) { - g(x); - } - } +void f(absl::StatusOr<int> x) { + if (x.ok()) { + g(x); + } +} +``` In such cases it is best to either pass the value directly when calling -a function or check that the status of the ``StatusOr<T>`` is ok in the +a function or check that the status of the `StatusOr<T>` is ok in the local scope of the callee. For example: -.. code:: cpp - - void g(int val) { - use(val); - } - - void f(absl::StatusOr<int> x) { - if (x.ok()) { - g(*x); - } - } +```cpp +void g(int val) { + use(val); +} -Aliases created via ``using`` declarations ------------------------------------------- +void f(absl::StatusOr<int> x) { + if (x.ok()) { + g(*x); + } +} +``` -The check is aware of aliases of ``StatusOr<T>`` types that are created -via ``using`` declarations. For example: +## Aliases created via `using` declarations -.. code:: cpp +The check is aware of aliases of `StatusOr<T>` types that are created +via `using` declarations. For example: - using StatusOrInt = absl::StatusOr<int>; +```cpp +using StatusOrInt = absl::StatusOr<int>; - void f(StatusOrInt x) { - use(*x); // unsafe: it is unclear whether the status of `x` is ok. - } +void f(StatusOrInt x) { + use(*x); // unsafe: it is unclear whether the status of `x` is ok. +} +``` -Containers ----------- +## Containers The check is more strict than necessary when it comes to containers of -``StatusOr<T>`` values. Simply checking that the status of an element of +`StatusOr<T>` values. Simply checking that the status of an element of a container is ok is not sufficient to deem accessing it safe. For example: -.. code:: cpp - - void f(std::vector<absl::StatusOr<int>> x) { - if (x[0].ok()) { - use(*x[0]); // unsafe: it is unclear whether the status of `x[0]` is ok. - } - } +```cpp +void f(std::vector<absl::StatusOr<int>> x) { + if (x[0].ok()) { + use(*x[0]); // unsafe: it is unclear whether the status of `x[0]` is ok. + } +} +``` One needs to grab a reference to a particular object and use that instead: -.. code:: cpp - - void f(std::vector<absl::StatusOr<int>> x) { - absl::StatusOr<int>& x0 = x[0]; - if (x0.ok()) { - use(*x0); - } - } +```cpp +void f(std::vector<absl::StatusOr<int>> x) { + absl::StatusOr<int>& x0 = x[0]; + if (x0.ok()) { + use(*x0); + } +} +``` A future version could improve the understanding of more safe usage patterns that involve containers. -Lambdas -------- +## Lambdas -The check is capable of reporting unsafe ``StatusOr<T>`` accesses in +The check is capable of reporting unsafe `StatusOr<T>` accesses in lambdas, but isn’t smart enough to propagate information from the surrounding context through the lambda. This means that the following pattern will be reported as an unsafe access: -.. code:: cpp - - void f(absl::StatusOr<int> x) { - if (x.ok()) { - [&x]() { - use(*x); // unsafe: it is unclear whether the status of `x` is ok. - } - } - } +```cpp +void f(absl::StatusOr<int> x) { + if (x.ok()) { + [&x]() { + use(*x); // unsafe: it is unclear whether the status of `x` is ok. + } + } +} +``` To avoid the issue, you should instead capture the contained object, either by value or by reference. An init-capture is useful for this, here capturing by reference: -.. code:: cpp - - void f(absl::StatusOr<int> x) { - if (x.ok()) { - [&x = *x]() { - use(x); - } - } - } +```cpp +void f(absl::StatusOr<int> x) { + if (x.ok()) { + [&x = *x]() { + use(x); + } + } +} +``` Alternatively you could add a check inside the lambda where the value is accessed: -.. code:: cpp - - void f(absl::StatusOr<int> x) { - [&x]() { - if (x.ok()) { - use(*x); - } - } - } +```cpp +void f(absl::StatusOr<int> x) { + [&x]() { + if (x.ok()) { + use(*x); + } + } +} +``` -Reasoning about integers ------------------------- +## Reasoning about integers Because it uses a simple SAT solver, the check cannot reason about integer inequalities. For instance, the following will result in a false positive: -.. code:: cpp - - void f(int n, absl::StatusOr<int> x) { - if (n > 0) - CHECK_OK(x); - if (n > 1) - return *x; // false positive - return 0; - } +```cpp +void f(int n, absl::StatusOr<int> x) { + if (n > 0) + CHECK_OK(x); + if (n > 1) + return *x; // false positive + return 0; +} +``` In fact, currently this is also the case if the two conditions are identical. diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/upgrade-duration-conversions.md b/clang-tools-extra/docs/clang-tidy/checks/abseil/upgrade-duration-conversions.md index 3abdd40b1b813..881b2a6fcfdf8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/upgrade-duration-conversions.md +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/upgrade-duration-conversions.md @@ -1,21 +1,21 @@ -.. title:: clang-tidy - abseil-upgrade-duration-conversions +```{title} clang-tidy - abseil-upgrade-duration-conversions +``` -abseil-upgrade-duration-conversions -=================================== +# abseil-upgrade-duration-conversions -Finds calls to ``absl::Duration`` arithmetic operators and factories whose +Finds calls to `absl::Duration` arithmetic operators and factories whose argument needs an explicit cast to continue compiling after upcoming API changes. -The operators ``*=``, ``/=``, ``*``, and ``/`` for ``absl::Duration`` currently +The operators `*=`, `/=`, `*`, and `/` for `absl::Duration` currently accept an argument of class type that is convertible to an arithmetic type. -Such a call currently converts the value to an ``int64_t``, even in a case such -as ``std::atomic<float>`` that would result in lossy conversion. +Such a call currently converts the value to an `int64_t`, even in a case such +as `std::atomic<float>` that would result in lossy conversion. -Additionally, the ``absl::Duration`` factory functions (``absl::Hours``, -``absl::Minutes``, etc) currently accept an ``int64_t`` or a floating-point +Additionally, the `absl::Duration` factory functions (`absl::Hours`, +`absl::Minutes`, etc) currently accept an `int64_t` or a floating-point type. Similar to the arithmetic operators, calls with an argument of class type -that is convertible to an arithmetic type go through the ``int64_t`` path. +that is convertible to an arithmetic type go through the `int64_t` path. These operators and factories will be changed to only accept arithmetic types to prevent unintended behavior. After these changes are released, passing an @@ -24,20 +24,20 @@ convertible to an arithmetic type. Here are example fixes created by this check: -.. code-block:: c++ - - std::atomic<int> a; - absl::Duration d = absl::Milliseconds(a); - d *= a; +```cpp +std::atomic<int> a; +absl::Duration d = absl::Milliseconds(a); +d *= a; +``` becomes -.. code-block:: c++ - - std::atomic<int> a; - absl::Duration d = absl::Milliseconds(static_cast<int64_t>(a)); - d *= static_cast<int64_t>(a); +```cpp +std::atomic<int> a; +absl::Duration d = absl::Milliseconds(static_cast<int64_t>(a)); +d *= static_cast<int64_t>(a); +``` -Note that this check always adds a cast to ``int64_t`` in order to preserve the +Note that this check always adds a cast to `int64_t` in order to preserve the current behavior of user code. It is possible that this uncovers unintended behavior due to types implicitly convertible to a floating-point type. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
