[PATCH] D75558: [clang-tidy] Update abseil-duration-unnecessary-conversion check to find more cases.
This revision was automatically updated to reflect the committed changes. Closed by commit rG3860b2a0bd09: [clang-tidy] Update Abseil Duration Conversion check to find more cases. (authored by hwright). Changed prior to commit: https://reviews.llvm.org/D75558?vs=247988=250252#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D75558/new/ https://reviews.llvm.org/D75558 Files: clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp Index: clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp === --- clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp +++ clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp @@ -100,6 +100,44 @@ d2 = VALUE(d1); #undef VALUE + // Multiplication + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Hours(absl::ToInt64Hours(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Nanoseconds(2 * absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Microseconds(2 * absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Milliseconds(2 * absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Seconds(2 * absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Minutes(2 * absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Hours(2 * absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + // These should not match d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); d2 = absl::Seconds(4); @@ -108,4 +146,6 @@ d2 = absl::Seconds(d1 / absl::Seconds(30)); d2 = absl::Hours(absl::FDivDuration(d1, absl::Minutes(1))); d2 = absl::Milliseconds(absl::FDivDuration(d1, absl::Milliseconds(20))); + d2 = absl::Seconds(absl::ToInt64Milliseconds(d1) * 2); + d2 = absl::Milliseconds(absl::ToDoubleSeconds(d1) * 2); } Index: clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst === --- clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst +++ clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst @@ -40,6 +40,17 @@ // 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); + + // Suggestion - Remove unnecessary conversion + absl::Duration d2 = d1 * 2; + Note: Converting to an integer and back to an ``absl::Duration`` might be a truncating
[PATCH] D75558: [clang-tidy] Update abseil-duration-unnecessary-conversion check to find more cases.
hwright created this revision. hwright added reviewers: aaron.ballman, ymandel. Herald added subscribers: cfe-commits, xazax.hun. Herald added a project: clang. This check now handles cases where there's a scalar multiplication happening between the two conversions. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D75558 Files: clang-tools-extra/clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp Index: clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp === --- clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp +++ clang-tools-extra/test/clang-tidy/checkers/abseil-duration-unnecessary-conversion.cpp @@ -100,6 +100,44 @@ d2 = VALUE(d1); #undef VALUE + // Multiplication + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Hours(absl::ToInt64Hours(d1) * 2); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 * 2 + d2 = absl::Nanoseconds(2 * absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Microseconds(2 * absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Milliseconds(2 * absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Seconds(2 * absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Minutes(2 * absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + d2 = absl::Hours(2 * absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = 2 * d1 + // These should not match d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); d2 = absl::Seconds(4); @@ -108,4 +146,6 @@ d2 = absl::Seconds(d1 / absl::Seconds(30)); d2 = absl::Hours(absl::FDivDuration(d1, absl::Minutes(1))); d2 = absl::Milliseconds(absl::FDivDuration(d1, absl::Milliseconds(20))); + d2 = absl::Seconds(absl::ToInt64Milliseconds(d1) * 2); + d2 = absl::Milliseconds(absl::ToDoubleSeconds(d1) * 2); } Index: clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst === --- clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst +++ clang-tools-extra/docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst @@ -40,6 +40,17 @@ // 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); + + // Suggestion - Remove unnecessary conversion + absl::Duration d2 = d1 * 2; + 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
[PATCH] D59183: [clang-tidy] Expand cases covered by the abseil-duration-unnecessary-conversion check
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE356141: [clang-tidy] Add additional patterns to the abseil-duration-unnecessary… (authored by hwright, committed by ). Changed prior to commit: https://reviews.llvm.org/D59183?vs=190456=190613#toc Repository: rCTE Clang Tools Extra CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59183/new/ https://reviews.llvm.org/D59183 Files: clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-unnecessary-conversion.cpp Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -21,6 +21,7 @@ template Duration operator*(Duration lhs, T rhs); template Duration operator*(T lhs, Duration rhs); template Duration operator/(Duration lhs, T rhs); +int64_t operator/(Duration lhs, Duration rhs); class Time{}; @@ -86,4 +87,6 @@ inline Time operator-(Time lhs, Duration rhs); inline Duration operator-(Time lhs, Time rhs); +double FDivDuration(Duration num, Duration den); + } // namespace absl Index: test/clang-tidy/abseil-duration-unnecessary-conversion.cpp === --- test/clang-tidy/abseil-duration-unnecessary-conversion.cpp +++ test/clang-tidy/abseil-duration-unnecessary-conversion.cpp @@ -8,42 +8,80 @@ // Floating point d2 = absl::Hours(absl::ToDoubleHours(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 // Integer point d2 = absl::Hours(absl::ToInt64Hours(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Minutes(absl::ToInt64Minutes(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Seconds(absl::ToInt64Seconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 + + d2 = absl::Hours(d1 / absl::Hours(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Minutes(d1 / absl::Minutes(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Seconds(d1 / absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration
[PATCH] D59183: [clang-tidy] Expand cases covered by the abseil-duration-unnecessary-conversion check
hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-unnecessary-conversion.cpp:48 + d2 = absl::Hours(d1 / absl::Hours(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] hokein wrote: > An off-topic comment: do we have this code pattern in the codebase? From my > understanding, the usage like this is really rare. This mostly shows up in migrations. When an existing API takes an integer, and caller already has a `Duration`, they sometimes use `dur / absl::Seconds(1)` to get back in integer at the callsite. After a migration, we end up with `absl::Seconds(dur /absl::Seconds(1))`, which should really just be `dur`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59183/new/ https://reviews.llvm.org/D59183 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59183: [clang-tidy] Expand cases covered by the abseil-duration-unnecessary-conversion check
hwright updated this revision to Diff 190456. hwright marked 4 inline comments as done. hwright added a comment. Addressed reviewer comments CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59183/new/ https://reviews.llvm.org/D59183 Files: clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-unnecessary-conversion.cpp Index: test/clang-tidy/abseil-duration-unnecessary-conversion.cpp === --- test/clang-tidy/abseil-duration-unnecessary-conversion.cpp +++ test/clang-tidy/abseil-duration-unnecessary-conversion.cpp @@ -8,42 +8,80 @@ // Floating point d2 = absl::Hours(absl::ToDoubleHours(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 // Integer point d2 = absl::Hours(absl::ToInt64Hours(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Minutes(absl::ToInt64Minutes(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Seconds(absl::ToInt64Seconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] - // CHECK-FIXES: d1 + // CHECK-FIXES: d2 = d1 + + d2 = absl::Hours(d1 / absl::Hours(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Minutes(d1 / absl::Minutes(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Seconds(d1 / absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Milliseconds(d1 / absl::Milliseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Microseconds(d1 / absl::Microseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + d2 = absl::Nanoseconds(d1 / absl::Nanoseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d2 = d1 + + d2 = absl::Hours(absl::FDivDuration(d1, absl::Hours(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning:
[PATCH] D58977: [clang-tidy] Add the abseil-time-comparison check
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE355835: [clang-tidy] Add the abseil-time-compare check (authored by hwright, committed by ). Changed prior to commit: https://reviews.llvm.org/D58977?vs=190075=190113#toc Repository: rCTE Clang Tools Extra CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58977/new/ https://reviews.llvm.org/D58977 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeComparisonCheck.cpp clang-tidy/abseil/TimeComparisonCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-comparison.cpp Index: clang-tidy/abseil/CMakeLists.txt === --- clang-tidy/abseil/CMakeLists.txt +++ clang-tidy/abseil/CMakeLists.txt @@ -17,6 +17,7 @@ RedundantStrcatCallsCheck.cpp StrCatAppendCheck.cpp StringFindStartswithCheck.cpp + TimeComparisonCheck.cpp TimeSubtractionCheck.cpp UpgradeDurationConversionsCheck.cpp Index: clang-tidy/abseil/TimeComparisonCheck.h === --- clang-tidy/abseil/TimeComparisonCheck.h +++ clang-tidy/abseil/TimeComparisonCheck.h @@ -0,0 +1,35 @@ +//===--- TimeComparisonCheck.h - clang-tidy -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMECOMPARECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMECOMPARECHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace abseil { + +/// Prefer comparison in the `absl::Time` domain instead of the numeric +/// domain. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-time-comparison.html +class TimeComparisonCheck : public ClangTidyCheck { +public: + TimeComparisonCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult ) override; +}; + +} // namespace abseil +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMECOMPARECHECK_H Index: clang-tidy/abseil/DurationComparisonCheck.cpp === --- clang-tidy/abseil/DurationComparisonCheck.cpp +++ clang-tidy/abseil/DurationComparisonCheck.cpp @@ -19,14 +19,10 @@ namespace abseil { void DurationComparisonCheck::registerMatchers(MatchFinder *Finder) { - auto Matcher = - binaryOperator(anyOf(hasOperatorName(">"), hasOperatorName(">="), - hasOperatorName("=="), hasOperatorName("<="), - hasOperatorName("<")), - hasEitherOperand(ignoringImpCasts(callExpr( - callee(functionDecl(DurationConversionFunction()) -.bind("function_decl")) - .bind("binop"); + auto Matcher = expr(comparisonOperatorWithCallee(functionDecl( + functionDecl(DurationConversionFunction()) + .bind("function_decl" + .bind("binop"); Finder->addMatcher(Matcher, this); } Index: clang-tidy/abseil/AbseilTidyModule.cpp === --- clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tidy/abseil/AbseilTidyModule.cpp @@ -23,6 +23,7 @@ #include "RedundantStrcatCallsCheck.h" #include "StringFindStartswithCheck.h" #include "StrCatAppendCheck.h" +#include "TimeComparisonCheck.h" #include "TimeSubtractionCheck.h" #include "UpgradeDurationConversionsCheck.h" @@ -60,6 +61,8 @@ "abseil-str-cat-append"); CheckFactories.registerCheck( "abseil-string-find-startswith"); +CheckFactories.registerCheck( +"abseil-time-comparison"); CheckFactories.registerCheck( "abseil-time-subtraction"); CheckFactories.registerCheck( Index: clang-tidy/abseil/TimeComparisonCheck.cpp === --- clang-tidy/abseil/TimeComparisonCheck.cpp +++ clang-tidy/abseil/TimeComparisonCheck.cpp @@ -0,0 +1,61 @@ +//===--- TimeComparisonCheck.cpp - clang-tidy +//===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +//
[PATCH] D58977: [clang-tidy] Add the abseil-time-comparison check
hwright updated this revision to Diff 190075. hwright marked an inline comment as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58977/new/ https://reviews.llvm.org/D58977 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeComparisonCheck.cpp clang-tidy/abseil/TimeComparisonCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-comparison.cpp Index: test/clang-tidy/abseil-time-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-comparison.cpp @@ -0,0 +1,129 @@ +// RUN: %check_clang_tidy %s abseil-time-comparison %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) > t1; + b = x >= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) >= t1; + b = x == absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1; + b = x <= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) <= t1; + b = x < absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) < t1; + b = x == absl::ToUnixSeconds(t1 - d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1 - d2; + b = absl::ToUnixSeconds(t1) > absl::ToUnixSeconds(t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > t2; + + // Check against the LHS + b = absl::ToUnixSeconds(t1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 <= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) == x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 == absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) >= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 >= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) > x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > absl::FromUnixSeconds(x); + + // Comparison against zero + b = absl::ToUnixSeconds(t1) < 0.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + b = absl::ToUnixSeconds(t1) < 0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + + // Scales other than Seconds + b = x > absl::ToUnixMicros(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMicros(x) > t1; + b = x >= absl::ToUnixMillis(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMillis(x) >= t1; + b = x == absl::ToUnixNanos(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixNanos(x) == t1; + b = x <= absl::ToUnixMinutes(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMinutes(x) <= t1; + b = x < absl::ToUnixHours(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixHours(x) < t1; + + // A long expression + bool some_condition; + int very_very_very_very_long_variable_name; + absl::Time SomeTime; + if (some_condition &&
[PATCH] D59183: [clang-tidy] Expand cases covered by the abseil-duration-unnecessary-conversion check
hwright created this revision. hwright added a reviewer: hokein. Herald added subscribers: cfe-commits, xazax.hun. Herald added a project: clang. This adds coverage for expressions of these forms absl::Duration d2, d1; d2 = absl::Seconds(d1 / absl::Seconds(1)); d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(1))); Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D59183 Files: clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-unnecessary-conversion.cpp Index: test/clang-tidy/abseil-duration-unnecessary-conversion.cpp === --- test/clang-tidy/abseil-duration-unnecessary-conversion.cpp +++ test/clang-tidy/abseil-duration-unnecessary-conversion.cpp @@ -45,6 +45,44 @@ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] // CHECK-FIXES: d1 + d2 = absl::Hours(d1 / absl::Hours(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(d1 / absl::Minutes(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(d1 / absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(d1 / absl::Milliseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(d1 / absl::Microseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(d1 / absl::Nanoseconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + + d2 = absl::Hours(absl::FDivDuration(d1, absl::Hours(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::FDivDuration(d1, absl::Minutes(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::FDivDuration(d1, absl::Milliseconds(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::FDivDuration(d1, absl::Microseconds(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::FDivDuration(d1, absl::Nanoseconds(1))); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove unnecessary absl::Duration conversions [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + // As macro argument #define PLUS_FIVE_S(x) x + absl::Seconds(5) d2 = PLUS_FIVE_S(absl::Seconds(absl::ToInt64Seconds(d1))); @@ -66,4 +104,8 @@ d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); d2 = absl::Seconds(4); int i = absl::ToInt64Milliseconds(d1); + d2 = absl::Hours(d1 / absl::Minutes(1)); + d2 = absl::Seconds(d1 / absl::Seconds(30)); + d2 = absl::Hours(absl::FDivDuration(d1, absl::Minutes(1))); + d2 = absl::Milliseconds(absl::FDivDuration(d1, absl::Milliseconds(20))); } Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -21,6 +21,7 @@ template Duration operator*(Duration lhs, T rhs); template Duration operator*(T lhs, Duration rhs); template Duration operator/(Duration lhs, T rhs); +int64_t operator/(Duration lhs, Duration rhs); class Time{}; @@ -86,4 +87,6 @@ inline Time operator-(Time lhs, Duration rhs); inline Duration operator-(Time lhs, Time rhs); +double FDivDuration(Duration num, Duration den); + } // namespace absl Index: docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst === ---
[PATCH] D58977: [clang-tidy] Add the abseil-time-comparison check
hwright updated this revision to Diff 189862. hwright marked 6 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58977/new/ https://reviews.llvm.org/D58977 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/TimeComparisonCheck.cpp clang-tidy/abseil/TimeComparisonCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-comparison.cpp Index: test/clang-tidy/abseil-time-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-comparison.cpp @@ -0,0 +1,129 @@ +// RUN: %check_clang_tidy %s abseil-time-comparison %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) > t1; + b = x >= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) >= t1; + b = x == absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1; + b = x <= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) <= t1; + b = x < absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) < t1; + b = x == absl::ToUnixSeconds(t1 - d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1 - d2; + b = absl::ToUnixSeconds(t1) > absl::ToUnixSeconds(t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > t2; + + // Check against the LHS + b = absl::ToUnixSeconds(t1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 <= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) == x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 == absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) >= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 >= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) > x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > absl::FromUnixSeconds(x); + + // Comparison against zero + b = absl::ToUnixSeconds(t1) < 0.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + b = absl::ToUnixSeconds(t1) < 0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + + // Scales other than Seconds + b = x > absl::ToUnixMicros(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMicros(x) > t1; + b = x >= absl::ToUnixMillis(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMillis(x) >= t1; + b = x == absl::ToUnixNanos(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixNanos(x) == t1; + b = x <= absl::ToUnixMinutes(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMinutes(x) <= t1; + b = x < absl::ToUnixHours(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixHours(x) < t1; + + // A long expression + bool some_condition; + int very_very_very_very_long_variable_name; + absl::Time SomeTime; + if (some_condition && very_very_very_very_long_variable_name + < absl::ToUnixSeconds(SomeTime)) { + // CHECK-MESSAGES:
[PATCH] D58977: [clang-tidy] Add the abseil-time-comparison check
hwright added inline comments. Comment at: clang-tidy/abseil/TimeComparisonCheck.cpp:23 + auto Matcher = + binaryOperator(anyOf(hasOperatorName(">"), hasOperatorName(">="), + hasOperatorName("=="), hasOperatorName("<="), ioeric wrote: > `DurationComparisonCheck.cpp` has a very similar matcher pattern. > > Maybe pull out a common matcher for this? E.g. > `comparisonOperatorWithCallee(...)`? > My one concern about doing so is that it would move the name bindings into a separate location away from the callback consuming those bindings. Since this is only the second instance of this pattern, would it be reasonable to wait until there's a third to combine them? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58977/new/ https://reviews.llvm.org/D58977 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58977: [clang-tidy] Add the abseil-time-comparison check
hwright created this revision. hwright added reviewers: hokein, ioeric. Herald added subscribers: cfe-commits, jdoerfert, xazax.hun, mgorny. Herald added a project: clang. This is an analog of the `abseil-duration-comparison` check, but for the `absl::Time` domain. It has a similar implementation and tests. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D58977 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/TimeComparisonCheck.cpp clang-tidy/abseil/TimeComparisonCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-comparison.cpp Index: test/clang-tidy/abseil-time-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-comparison.cpp @@ -0,0 +1,129 @@ +// RUN: %check_clang_tidy %s abseil-time-comparison %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) > t1; + b = x >= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) >= t1; + b = x == absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1; + b = x <= absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) <= t1; + b = x < absl::ToUnixSeconds(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) < t1; + b = x == absl::ToUnixSeconds(t1 - d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixSeconds(x) == t1 - d2; + b = absl::ToUnixSeconds(t1) > absl::ToUnixSeconds(t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > t2; + + // Check against the LHS + b = absl::ToUnixSeconds(t1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 <= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) == x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 == absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) >= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 >= absl::FromUnixSeconds(x); + b = absl::ToUnixSeconds(t1) > x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 > absl::FromUnixSeconds(x); + + // Comparison against zero + b = absl::ToUnixSeconds(t1) < 0.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + b = absl::ToUnixSeconds(t1) < 0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: t1 < absl::UnixEpoch(); + + // Scales other than Seconds + b = x > absl::ToUnixMicros(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMicros(x) > t1; + b = x >= absl::ToUnixMillis(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMillis(x) >= t1; + b = x == absl::ToUnixNanos(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixNanos(x) == t1; + b = x <= absl::ToUnixMinutes(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixMinutes(x) <= t1; + b = x < absl::ToUnixHours(t1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the time domain [abseil-time-comparison] + // CHECK-FIXES: absl::FromUnixHours(x) < t1; + + // A long expression + bool some_condition; + int
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE355024: [clang-tidy] Add the abseil-time-subtraction check (authored by hwright, committed by ). Repository: rCTE Clang Tools Extra CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- test/clang-tidy/abseil-time-subtraction.cpp +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,117 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x) / 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)) / 5; + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // More complex subexpressions + d = absl::Hours(absl::ToUnixHours(t) - 5 * x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + //
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright marked an inline comment as done. hwright added inline comments. Comment at: clang-tidy/abseil/TimeSubtractionCheck.cpp:97 +void TimeSubtractionCheck::check(const MatchFinder::MatchResult ) { + const auto *BinOp = Result.Nodes.getNodeAs("binop"); + std::string inverse_name = hwright wrote: > JonasToth wrote: > > hwright wrote: > > > JonasToth wrote: > > > > Could you please split this function up into smaller ones. There are > > > > three or four distinct cases that are easier to comprehend in isolation. > > > The actual bodies of these if-statements are only one or two separate > > > statements themselves. Moving those to separate functions seems like it > > > would just obfuscate things a bit. > > IMHO they are complicated statements and hide what is being done. Wrapping > > them in a function with a name that states what is done seems appropriate. > I would agree that they are complicated statements, which is why there are > multi-line comments explaining what is being doing. Moving a two-line > compound statement into a separate function which is only called once seems > more confusing than simplifying. More information can be expressed in a > prose comment than a single concise function name, no? I've pulled out the common duplicated functionality which actually emits the diagnostic, and I think that's simplified these branches a bit more. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright updated this revision to Diff 188372. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,117 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x) / 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)) / 5; + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // More complex subexpressions + d = absl::Hours(absl::ToUnixHours(t) - 5 * x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(5 * x)); + + // These should not trigger; they are likely bugs + d = absl::Milliseconds(absl::ToUnixSeconds(t) - x); + d = absl::Seconds(absl::ToUnixMicros(t) - x); + + //
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/TimeSubtractionCheck.cpp:97 +void TimeSubtractionCheck::check(const MatchFinder::MatchResult ) { + const auto *BinOp = Result.Nodes.getNodeAs("binop"); + std::string inverse_name = JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > Could you please split this function up into smaller ones. There are > > > three or four distinct cases that are easier to comprehend in isolation. > > The actual bodies of these if-statements are only one or two separate > > statements themselves. Moving those to separate functions seems like it > > would just obfuscate things a bit. > IMHO they are complicated statements and hide what is being done. Wrapping > them in a function with a name that states what is done seems appropriate. I would agree that they are complicated statements, which is why there are multi-line comments explaining what is being doing. Moving a two-line compound statement into a separate function which is only called once seems more confusing than simplifying. More information can be expressed in a prose comment than a single concise function name, no? Comment at: test/clang-tidy/abseil-time-subtraction.cpp:12 + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > please add tests where `x` itself is a calculation with different > > > precedence of its operators (multiplication, addition) to ensure these > > > cases are transformed properly as well. > > This doesn't actually matter in this case: `x` will be wrapped in a > > function call. > > > > It does matter in the case where we //unwrap// the first argument (below) > > and I've already got a test which uses multiplication in this case. I've > > also added one for division. > Yes, it should not matter if `x` is an expr itself or just a variable. Thats > why it should be tested its actually true. Added, though this seems more a test of the matcher infrastructure than the tool itself. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright updated this revision to Diff 188289. hwright marked 5 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,117 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x) / 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)) / 5; + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // More complex subexpressions + d = absl::Hours(absl::ToUnixHours(t) - 5 * x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(5 * x)); + + // These should not trigger; they are likely bugs + d = absl::Milliseconds(absl::ToUnixSeconds(t) - x); + d =
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/TimeSubtractionCheck.cpp:97 +void TimeSubtractionCheck::check(const MatchFinder::MatchResult ) { + const auto *BinOp = Result.Nodes.getNodeAs("binop"); + std::string inverse_name = JonasToth wrote: > Could you please split this function up into smaller ones. There are three or > four distinct cases that are easier to comprehend in isolation. The actual bodies of these if-statements are only one or two separate statements themselves. Moving those to separate functions seems like it would just obfuscate things a bit. Comment at: clang-tidy/abseil/TimeSubtractionCheck.h:19 +/// Finds and fixes `absl::Time` subtraction expressions to do subtraction +/// in the Time domain instead of the numeric domain. +/// JonasToth wrote: > nit: 'Time' domain This doesn't refer to a type, but a library system, so it probably isn't appropriate to quote it. (Just has how one wouldn't quote "frequency" when talking about "the frequency domain" of a Fourier transform.) Comment at: test/clang-tidy/abseil-time-subtraction.cpp:12 + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] JonasToth wrote: > please add tests where `x` itself is a calculation with different precedence > of its operators (multiplication, addition) to ensure these cases are > transformed properly as well. This doesn't actually matter in this case: `x` will be wrapped in a function call. It does matter in the case where we //unwrap// the first argument (below) and I've already got a test which uses multiplication in this case. I've also added one for division. Comment at: test/clang-tidy/abseil-time-subtraction.cpp:78 + // CHECK-FIXES: return absl::FromUnixSeconds(x) - t; +} JonasToth wrote: > please add tests for templates and macros. I've add tests for macros, though I'm not sure what cases you have in mind regarding templates. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright updated this revision to Diff 187967. hwright marked 15 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,112 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x) / 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)) / 5; + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // These should not trigger; they are likely bugs + d = absl::Milliseconds(absl::ToUnixSeconds(t) - x); + d = absl::Seconds(absl::ToUnixMicros(t) - x); + + // Various macro scenarios +#define SUB(z, t1) z - absl::ToUnixSeconds(t1) + y = SUB(x, t); +#undef SUB + +#define MILLIS(t1) absl::ToUnixMillis(t1) + y = x - MILLIS(t); +#undef MILLIS + +#define HOURS(z)
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright updated this revision to Diff 186569. hwright marked 3 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58137/new/ https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // These should not trigger; they are likely bugs + d = absl::Milliseconds(absl::ToUnixSeconds(t) - x); + d = absl::Seconds(absl::ToUnixMicros(t) - x); +} + +absl::Duration parens_in_return() { + absl::Time t; + int x; + + return absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: return t - absl::FromUnixSeconds(x); + return absl::Seconds(x - absl::ToUnixSeconds(t)); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: return
[PATCH] D58137: [clang-tidy] Add the abseil-time-subtraction check
hwright created this revision. hwright added reviewers: ioeric, hokein, JonasToth, aaron.ballman. hwright added a project: clang-tools-extra. Herald added subscribers: cfe-commits, jdoerfert, xazax.hun, mgorny. Herald added a project: clang. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D58137 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/TimeSubtractionCheck.cpp clang-tidy/abseil/TimeSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-time-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-time-subtraction.cpp Index: test/clang-tidy/abseil-time-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-time-subtraction.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s abseil-time-subtraction %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void g(absl::Duration d); + +void f() { + absl::Time t; + int x, y; + absl::Duration d; + + d = absl::Hours(absl::ToUnixHours(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixHours(x)); + d = absl::Minutes(absl::ToUnixMinutes(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMinutes(x)); + d = absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixSeconds(x)); + d = absl::Milliseconds(absl::ToUnixMillis(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMillis(x)); + d = absl::Microseconds(absl::ToUnixMicros(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixMicros(x)); + d = absl::Nanoseconds(absl::ToUnixNanos(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = (t - absl::FromUnixNanos(x)); + + y = x - absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Hours(absl::FromUnixHours(x) - t); + y = x - absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Minutes(absl::FromUnixMinutes(x) - t); + y = x - absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t); + y = x - absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Milliseconds(absl::FromUnixMillis(x) - t); + y = x - absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Microseconds(absl::FromUnixMicros(x) - t); + y = x - absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: y = absl::ToInt64Nanoseconds(absl::FromUnixNanos(x) - t); + + // Check parenthesis placement + d = 5 * absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: d = 5 * (t - absl::FromUnixSeconds(x)); + + // No extra parens around arguments + g(absl::Seconds(absl::ToUnixSeconds(t) - x)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(t - absl::FromUnixSeconds(x)); + g(absl::Seconds(x - absl::ToUnixSeconds(t))); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: g(absl::FromUnixSeconds(x) - t); + + // These should not trigger; they are likely bugs + d = absl::Milliseconds(absl::ToUnixSeconds(t) - x); + d = absl::Seconds(absl::ToUnixMicros(t) - x); +} + +absl::Duration parens_in_return() { + absl::Time t; + int x; + + return absl::Seconds(absl::ToUnixSeconds(t) - x); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: perform subtraction in the time domain [abseil-time-subtraction] + // CHECK-FIXES: return t - absl::FromUnixSeconds(x); + return absl::Seconds(x - absl::ToUnixSeconds(t)); + // CHECK-MESSAGES:
[PATCH] D57353: [clang-tidy] Add the abseil-duration-unnecessary-conversion check
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE353079: [clang-tidy] Add the abseil-duration-unnecessary-conversion check (authored by hwright, committed by ). Herald added a project: clang. Changed prior to commit: https://reviews.llvm.org/D57353?vs=185057=185104#toc Repository: rCTE Clang Tools Extra CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp clang-tidy/abseil/DurationUnnecessaryConversionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-unnecessary-conversion.cpp Index: clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp === --- clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp +++ clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp @@ -0,0 +1,58 @@ +//===--- DurationUnnecessaryConversionCheck.cpp - clang-tidy +//---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "DurationUnnecessaryConversionCheck.h" +#include "DurationRewriter.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace abseil { + +void DurationUnnecessaryConversionCheck::registerMatchers(MatchFinder *Finder) { + for (const auto : {"Hours", "Minutes", "Seconds", "Milliseconds", +"Microseconds", "Nanoseconds"}) { +std::string DurationFactory = (llvm::Twine("::absl::") + Scale).str(); +std::string FloatConversion = +(llvm::Twine("::absl::ToDouble") + Scale).str(); +std::string IntegerConversion = +(llvm::Twine("::absl::ToInt64") + Scale).str(); + +Finder->addMatcher( +callExpr( +callee(functionDecl(hasName(DurationFactory))), +hasArgument(0, callExpr(callee(functionDecl(hasAnyName( +FloatConversion, IntegerConversion))), +hasArgument(0, expr().bind("arg") +.bind("call"), +this); + } +} + +void DurationUnnecessaryConversionCheck::check( +const MatchFinder::MatchResult ) { + const auto *OuterCall = Result.Nodes.getNodeAs("call"); + const auto *Arg = Result.Nodes.getNodeAs("arg"); + + if (!isNotInMacro(Result, OuterCall)) +return; + + diag(OuterCall->getBeginLoc(), "remove unnecessary absl::Duration conversions") + << FixItHint::CreateReplacement( + OuterCall->getSourceRange(), + tooling::fixit::getText(*Arg, *Result.Context)); +} + +} // namespace abseil +} // namespace tidy +} // namespace clang Index: clang-tidy/abseil/CMakeLists.txt === --- clang-tidy/abseil/CMakeLists.txt +++ clang-tidy/abseil/CMakeLists.txt @@ -10,6 +10,7 @@ DurationFactoryScaleCheck.cpp DurationRewriter.cpp DurationSubtractionCheck.cpp + DurationUnnecessaryConversionCheck.cpp FasterStrsplitDelimiterCheck.cpp NoInternalDependenciesCheck.cpp NoNamespaceCheck.cpp Index: clang-tidy/abseil/DurationUnnecessaryConversionCheck.h === --- clang-tidy/abseil/DurationUnnecessaryConversionCheck.h +++ clang-tidy/abseil/DurationUnnecessaryConversionCheck.h @@ -0,0 +1,35 @@ +//===--- DurationUnnecessaryConversionCheck.h - clang-tidy --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMEDOUBLECONVERSIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMEDOUBLECONVERSIONCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace abseil { + +/// Finds and fixes cases where ``absl::Duration`` values are being converted +/// to numeric types and back again. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-unnecessary-conversion.html +class DurationUnnecessaryConversionCheck : public ClangTidyCheck { +public: + DurationUnnecessaryConversionCheck(StringRef Name, ClangTidyContext
[PATCH] D57353: [clang-tidy] Add the abseil-duration-unnecessary-conversion check
hwright added a comment. @hokein Thanks for the suggestion on the name, I was looking for something a little less confusing. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57353: [clang-tidy] Add the abseil-duration-unnecessary-conversion check
hwright updated this revision to Diff 185057. hwright marked 4 inline comments as done. hwright retitled this revision from "[clang-tidy] Add the abseil-duration-double-conversion check" to "[clang-tidy] Add the abseil-duration-unnecessary-conversion check". hwright added a comment. Renamed to `abseil-duration-unnecessary-conversion` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationUnnecessaryConversionCheck.cpp clang-tidy/abseil/DurationUnnecessaryConversionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-unnecessary-conversion.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-unnecessary-conversion.cpp Index: test/clang-tidy/abseil-duration-unnecessary-conversion.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-unnecessary-conversion.cpp @@ -0,0 +1,69 @@ +// RUN: %check_clang_tidy %s abseil-duration-unnecessary-conversion %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1, d2; + + // Floating point + d2 = absl::Hours(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + + // Integer point + d2 = absl::Hours(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: d1 + + // As macro argument +#define PLUS_FIVE_S(x) x + absl::Seconds(5) + d2 = PLUS_FIVE_S(absl::Seconds(absl::ToInt64Seconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: remove double conversion of absl::Duration [abseil-duration-unnecessary-conversion] + // CHECK-FIXES: PLUS_FIVE_S(d1) +#undef PLUS_FIVE_S + + // Split by macro: should not change +#define TOSECONDS(x) absl::Seconds(x) + d2 = TOSECONDS(absl::ToInt64Seconds(d1)); +#undef TOSECONDS + + // Don't change something inside a macro definition +#define VALUE(x) absl::Hours(absl::ToInt64Hours(x)); + d2 = VALUE(d1); +#undef VALUE + + // These should not match + d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); + d2 = absl::Seconds(4); + int i = absl::ToInt64Milliseconds(d1); +} Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -14,6 +14,8 @@ Duration /=(float r); Duration /=(double r); template Duration /=(T r); + + Duration +(Duration d); }; template Duration operator*(Duration lhs, T rhs); Index: docs/clang-tidy/checks/list.rst
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright marked 2 inline comments as done. hwright added inline comments. Comment at: docs/clang-tidy/checks/abseil-duration-double-conversion.rst:20 + + + // Original - Conversion to integer and back again MyDeveloperDay wrote: > hwright wrote: > > Eugene.Zelenko wrote: > > > Unnecessary empty line. > > This is consistent with other documentation in this directory, such as > > `abseil-faster-strsplit-delimiter.rst`. > In your example `abseil-faster-strsplit-delimiter.rst` , The double blank > line in the html doesn't give much delineation between the before and after > code and the next example. > > {F7867869} > > There probably isn't a convention per say (which is a shame), across the docs > we do a mixture of different styles > > https://clang.llvm.org/extra/clang-tidy/checks/readability-braces-around-statements.html > https://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-accept.html > https://clang.llvm.org/extra/clang-tidy/checks/google-objc-function-naming.html > > But there is a desire by some of the regular clang-tidy reviewers to make the > documentation consistent > > It may not be ideal but the "Before/After" style, that is used in > `modernize-use-emplace`, > `modernize-use-using`,`readability-braces-around-statements`,`readability-identifier-naming` > and `readability-redundant-function-ptr-dereference` does help a little. > > I'm not saying looks better, but I've added a couple of examples of > formatting the strsplit example for comparison, feel free to ignore. > > {F7867960} > > {F7868028} > > I like those examples! Would it be reasonable to update all of the `abseil-duration-*` documentation in a separate pass, after this change is submitted? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright added inline comments. Comment at: docs/clang-tidy/checks/abseil-duration-double-conversion.rst:28 + +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. Eugene.Zelenko wrote: > Please use `` for language constructs. Same below. Thanks; I thought I'd caught them all. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright updated this revision to Diff 184146. hwright marked 2 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationDoubleConversionCheck.cpp clang-tidy/abseil/DurationDoubleConversionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-double-conversion.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-double-conversion.cpp Index: test/clang-tidy/abseil-duration-double-conversion.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-double-conversion.cpp @@ -0,0 +1,69 @@ +// RUN: %check_clang_tidy %s abseil-duration-double-conversion %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1, d2; + + // Floating point + d2 = absl::Hours(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // Integer point + d2 = absl::Hours(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // As macro argument +#define PLUS_FIVE_S(x) x + absl::Seconds(5) + d2 = PLUS_FIVE_S(absl::Seconds(absl::ToInt64Seconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: PLUS_FIVE_S(d1) +#undef PLUS_FIVE_S + + // Split by macro: should not change +#define TOSECONDS(x) absl::Seconds(x) + d2 = TOSECONDS(absl::ToInt64Seconds(d1)); +#undef TOSECONDS + + // Don't change something inside a macro definition +#define VALUE(x) absl::Hours(absl::ToInt64Hours(x)); + d2 = VALUE(d1); +#undef VALUE + + // These should not match + d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); + d2 = absl::Seconds(4); + int i = absl::ToInt64Milliseconds(d1); +} Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -14,6 +14,8 @@ Duration /=(float r); Duration /=(double r); template Duration /=(T r); + + Duration +(Duration d); }; template Duration operator*(Duration lhs, T rhs); Index: docs/clang-tidy/checks/list.rst === --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-comparison abseil-duration-conversion-cast abseil-duration-division + abseil-duration-double-conversion abseil-duration-factory-float abseil-duration-factory-scale
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright added inline comments. Comment at: docs/clang-tidy/checks/abseil-duration-double-conversion.rst:20 + + + // Original - Conversion to integer and back again Eugene.Zelenko wrote: > Unnecessary empty line. This is consistent with other documentation in this directory, such as `abseil-faster-strsplit-delimiter.rst`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright updated this revision to Diff 184143. hwright marked 5 inline comments as done. hwright added a comment. Address reviewer comments. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57353/new/ https://reviews.llvm.org/D57353 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationDoubleConversionCheck.cpp clang-tidy/abseil/DurationDoubleConversionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-double-conversion.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-double-conversion.cpp Index: test/clang-tidy/abseil-duration-double-conversion.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-double-conversion.cpp @@ -0,0 +1,69 @@ +// RUN: %check_clang_tidy %s abseil-duration-double-conversion %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1, d2; + + // Floating point + d2 = absl::Hours(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // Integer point + d2 = absl::Hours(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // As macro argument +#define PLUS_FIVE_S(x) x + absl::Seconds(5) + d2 = PLUS_FIVE_S(absl::Seconds(absl::ToInt64Seconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: PLUS_FIVE_S(d1) +#undef PLUS_FIVE_S + + // Split by macro: should not change +#define TOSECONDS(x) absl::Seconds(x) + d2 = TOSECONDS(absl::ToInt64Seconds(d1)); +#undef TOSECONDS + + // Don't change something inside a macro definition +#define VALUE(x) absl::Hours(absl::ToInt64Hours(x)); + d2 = VALUE(d1); +#undef VALUE + + // These should not match + d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); + d2 = absl::Seconds(4); + int i = absl::ToInt64Milliseconds(d1); +} Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -14,6 +14,8 @@ Duration /=(float r); Duration /=(double r); template Duration /=(T r); + + Duration +(Duration d); }; template Duration operator*(Duration lhs, T rhs); Index: docs/clang-tidy/checks/list.rst === --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-comparison abseil-duration-conversion-cast abseil-duration-division + abseil-duration-double-conversion abseil-duration-factory-float
[PATCH] D57353: [clang-tidy] Add the abseil-duration-double-conversion check
hwright created this revision. hwright added reviewers: hokein, JonasToth, aaron.ballman. hwright added a project: clang-tools-extra. Herald added subscribers: cfe-commits, xazax.hun, mgorny. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D57353 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationDoubleConversionCheck.cpp clang-tidy/abseil/DurationDoubleConversionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-double-conversion.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-double-conversion.cpp Index: test/clang-tidy/abseil-duration-double-conversion.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-double-conversion.cpp @@ -0,0 +1,69 @@ +// RUN: %check_clang_tidy %s abseil-duration-double-conversion %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1, d2; + + // Floating point + d2 = absl::Hours(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // Integer point + d2 = absl::Hours(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Minutes(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Seconds(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Milliseconds(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Microseconds(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + d2 = absl::Nanoseconds(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: d1 + + // As macro argument +#define PLUS_FIVE_S(x) x + absl::Seconds(5) + d2 = PLUS_FIVE_S(absl::Seconds(absl::ToInt64Seconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: remove double conversion of absl::Duration [abseil-duration-double-conversion] + // CHECK-FIXES: PLUS_FIVE_S(d1) +#undef PLUS_FIVE_S + + // Split by macro: should not change +#define TOSECONDS(x) absl::Seconds(x) + d2 = TOSECONDS(absl::ToInt64Seconds(d1)); +#undef TOSECONDS + + // Don't change something inside a macro definition +#define VALUE(x) absl::Hours(absl::ToInt64Hours(x)); + d2 = VALUE(d1); +#undef VALUE + + // These should not match + d2 = absl::Seconds(absl::ToDoubleMilliseconds(d1)); + d2 = absl::Seconds(4); + int i = absl::ToInt64Milliseconds(d1); +} Index: test/clang-tidy/Inputs/absl/time/time.h === --- test/clang-tidy/Inputs/absl/time/time.h +++ test/clang-tidy/Inputs/absl/time/time.h @@ -14,6 +14,8 @@ Duration /=(float r); Duration /=(double r); template Duration /=(T r); + + Duration +(Duration d); }; template Duration operator*(Duration lhs, T rhs); Index: docs/clang-tidy/checks/list.rst === --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-comparison abseil-duration-conversion-cast abseil-duration-division + abseil-duration-double-conversion
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
This revision was automatically updated to reflect the committed changes. Closed by commit rL352362: [clang-tidy] Add the abseil-duration-addition check (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D57185?vs=183583=183840#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 Files: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/abseil/DurationAdditionCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationAdditionCheck.h clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h clang-tools-extra/trunk/docs/ReleaseNotes.rst clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-addition.rst clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst clang-tools-extra/trunk/test/clang-tidy/Inputs/absl/time/time.h clang-tools-extra/trunk/test/clang-tidy/abseil-duration-addition.cpp Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp @@ -103,6 +103,25 @@ llvm_unreachable("unknown scaling factor"); } +/// Returns the Time factory function name for a given `Scale`. +llvm::StringRef getTimeFactoryForScale(DurationScale scale) { + switch (scale) { + case DurationScale::Hours: +return "absl::ToUnixHours"; + case DurationScale::Minutes: +return "absl::ToUnixMinutes"; + case DurationScale::Seconds: +return "absl::ToUnixSeconds"; + case DurationScale::Milliseconds: +return "absl::ToUnixMillis"; + case DurationScale::Microseconds: +return "absl::ToUnixMicros"; + case DurationScale::Nanoseconds: +return "absl::ToUnixNanos"; + } + llvm_unreachable("unknown scaling factor"); +} + /// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult , const Expr ) { auto ZeroMatcher = @@ -197,6 +216,22 @@ return ScaleIter->second; } +llvm::Optional getScaleForTimeInverse(llvm::StringRef Name) { + static const llvm::StringMap ScaleMap( + {{"ToUnixHours", DurationScale::Hours}, + {"ToUnixMinutes", DurationScale::Minutes}, + {"ToUnixSeconds", DurationScale::Seconds}, + {"ToUnixMillis", DurationScale::Milliseconds}, + {"ToUnixMicros", DurationScale::Microseconds}, + {"ToUnixNanos", DurationScale::Nanoseconds}}); + + auto ScaleIter = ScaleMap.find(std::string(Name)); + if (ScaleIter == ScaleMap.end()) +return llvm::None; + + return ScaleIter->second; +} + std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node) { Index: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "DurationAdditionCheck.h" #include "DurationComparisonCheck.h" #include "DurationConversionCastCheck.h" #include "DurationDivisionCheck.h" @@ -30,6 +31,8 @@ class AbseilModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories ) override { +CheckFactories.registerCheck( +"abseil-duration-addition"); CheckFactories.registerCheck( "abseil-duration-comparison"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationAdditionCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationAdditionCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationAdditionCheck.cpp @@ -0,0 +1,73 @@ +//===--- DurationAdditionCheck.cpp - clang-tidy===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "DurationAdditionCheck.h" +#include "DurationRewriter.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace abseil { + +void DurationAdditionCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( +
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright updated this revision to Diff 183583. hwright marked an inline comment as done. hwright added a comment. Add another test CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationAdditionCheck.cpp clang-tidy/abseil/DurationAdditionCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-addition.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-addition.cpp Index: test/clang-tidy/abseil-duration-addition.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-addition.cpp @@ -0,0 +1,98 @@ +// RUN: %check_clang_tidy %s abseil-duration-addition %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Time t; + int i; + + i = absl::ToUnixHours(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(t + absl::Hours(5)) + i = absl::ToUnixMinutes(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(t + absl::Minutes(5)) + i = absl::ToUnixSeconds(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + i = absl::ToUnixMillis(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(t + absl::Milliseconds(5)) + i = absl::ToUnixMicros(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Microseconds(5)) + i = absl::ToUnixNanos(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(t + absl::Nanoseconds(5)) + + i = 3 + absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + i = 3 + absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(absl::Minutes(3) + t) + i = 3 + absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(absl::Seconds(3) + t) + i = 3 + absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(absl::Milliseconds(3) + t) + i = 3 + absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(absl::Microseconds(3) + t) + i = 3 + absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(absl::Nanoseconds(3) + t) + + // Undoing inverse conversions + i = absl::ToUnixMicros(t) + absl::ToInt64Microseconds(absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Seconds(1)) + + // Parens + i = 3 + (absl::ToUnixHours(t)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + + // Float folding + i = absl::ToUnixSeconds(t) + 5.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::FromUnixSeconds(30) + i = absl::ToUnixSeconds(THIRTY) + 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(THIRTY + absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToUnixSeconds(t) + 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(1)) + + // These should not match + i = 5 + 6; + i = absl::ToUnixSeconds(t) - 1.0; + i = absl::ToUnixSeconds(t) * 1.0; + i =
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright marked 2 inline comments as done. hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-addition.cpp:84 +#undef PLUS_FIVE +} JonasToth wrote: > a view template test-cases would be good to have. I'm not sure I know that terminology; do you have an example? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationAdditionCheck.cpp:22 +void DurationAdditionCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + binaryOperator(hasOperatorName("+"), JonasToth wrote: > This whole file is structurally similar to the `DurationSubtractionCheck.cpp` > equivalent (which is expected :)), maybe some parts could be refactored out? > Will there be a check for duration scaling or the like? I think that most of it already has been factored out (e.g., `rewriteExprFromNumberToDuration` and `getScaleForTimeInverse`, etc) . The actual meat here is pretty light: the matcher, and then the diagnostic generation. A scaling change may also follow. Our experience has been that scaling isn't quite straight forward, as the scaling factor may have semantic meaning which changes the result, but which isn't captured by the type system. Probably not a design discussion to have here, but suffice it to say that I don't know if this is yet settled. Comment at: clang-tidy/abseil/DurationAdditionCheck.cpp:50 +diag(Binop->getBeginLoc(), "perform addition in the duration domain") +<< FixItHint::CreateReplacement( + Binop->getSourceRange(), JonasToth wrote: > The only difference between the two `diag` seems to be the `FixItHint`. I > would rather refactor the diag out of the `if`. This doesn't really de-dupe very much, since the bulk of the work here is creating the `FixItHint`. Done. Comment at: clang-tidy/abseil/DurationAdditionCheck.cpp:60 + } else { +assert(Call == Binop->getRHS()->IgnoreImpCast() && "Call should be found on the RHS"); +diag(Binop->getBeginLoc(), "perform addition in the duration domain") JonasToth wrote: > What happens with paren-casts, are they ignored as well? (See one comment in > the test-cases) Now they are. Comment at: test/clang-tidy/abseil-duration-addition.cpp:28 + + i = 3 + absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] JonasToth wrote: > Call is on the right side, what happens for `3 + (abs::ToUnixHours(t));` Added this test, and updated to ignore paren casts. Comment at: test/clang-tidy/abseil-duration-addition.cpp:48 + // Undoing inverse conversions + i = absl::ToUnixMicros(t) + absl::ToInt64Microseconds(absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] JonasToth wrote: > Is something like this > ``` > i += absl::ToInt64MicroSeconds(absl::Seconds(1)); > ``` > possible (syntactically and semantically)? > The compound operators are currently not covered by this (and the > subtraction-check), but in this case it looks like a possible use-case. Semantically, this is possible, but wouldn't fall under this transform, since it would require changing the type of `i`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright updated this revision to Diff 183539. hwright marked 11 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationAdditionCheck.cpp clang-tidy/abseil/DurationAdditionCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-addition.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-addition.cpp Index: test/clang-tidy/abseil-duration-addition.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-addition.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s abseil-duration-addition %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Time t; + int i; + + i = absl::ToUnixHours(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(t + absl::Hours(5)) + i = absl::ToUnixMinutes(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(t + absl::Minutes(5)) + i = absl::ToUnixSeconds(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + i = absl::ToUnixMillis(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(t + absl::Milliseconds(5)) + i = absl::ToUnixMicros(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Microseconds(5)) + i = absl::ToUnixNanos(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(t + absl::Nanoseconds(5)) + + i = 3 + absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + i = 3 + absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(absl::Minutes(3) + t) + i = 3 + absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(absl::Seconds(3) + t) + i = 3 + absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(absl::Milliseconds(3) + t) + i = 3 + absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(absl::Microseconds(3) + t) + i = 3 + absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(absl::Nanoseconds(3) + t) + + // Undoing inverse conversions + i = absl::ToUnixMicros(t) + absl::ToInt64Microseconds(absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Seconds(1)) + + // Parens + i = 3 + (absl::ToUnixHours(t)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + + // Float folding + i = absl::ToUnixSeconds(t) + 5.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::FromUnixSeconds(30) + i = absl::ToUnixSeconds(THIRTY) + 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(THIRTY + absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToUnixSeconds(t) + 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(1)) + + // These should not match + i = 5 + 6; + i = absl::ToUnixSeconds(t) - 1.0; + i = absl::ToUnixSeconds(t) * 1.0; + i = absl::ToUnixSeconds(t) / 1.0; + i +=
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright updated this revision to Diff 183531. hwright added a comment. Sort release notes CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57185/new/ https://reviews.llvm.org/D57185 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationAdditionCheck.cpp clang-tidy/abseil/DurationAdditionCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-addition.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-addition.cpp Index: test/clang-tidy/abseil-duration-addition.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-addition.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s abseil-duration-addition %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Time t; + int i; + + i = absl::ToUnixHours(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(t + absl::Hours(5)) + i = absl::ToUnixMinutes(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(t + absl::Minutes(5)) + i = absl::ToUnixSeconds(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + i = absl::ToUnixMillis(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(t + absl::Milliseconds(5)) + i = absl::ToUnixMicros(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Microseconds(5)) + i = absl::ToUnixNanos(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(t + absl::Nanoseconds(5)) + + i = 3 + absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + i = 3 + absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(absl::Minutes(3) + t) + i = 3 + absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(absl::Seconds(3) + t) + i = 3 + absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(absl::Milliseconds(3) + t) + i = 3 + absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(absl::Microseconds(3) + t) + i = 3 + absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(absl::Nanoseconds(3) + t) + + // Undoing inverse conversions + i = absl::ToUnixMicros(t) + absl::ToInt64Microseconds(absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Seconds(1)) + + // Float folding + i = absl::ToUnixSeconds(t) + 5.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::FromUnixSeconds(30) + i = absl::ToUnixSeconds(THIRTY) + 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(THIRTY + absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToUnixSeconds(t) + 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(1)) + + // These should not match + i = 5 + 6; + i = absl::ToUnixSeconds(t) - 1.0; + i = absl::ToUnixSeconds(t) * 1.0; + i = absl::ToUnixSeconds(t) / 1.0; + +#define PLUS_FIVE(z) absl::ToUnixSeconds(z) + 5 + i = PLUS_FIVE(t); +#undef PLUS_FIVE +} Index: test/clang-tidy/Inputs/absl/time/time.h === ---
[PATCH] D57185: [clang-tidy] Add the abseil-duration-addition check
hwright created this revision. hwright added reviewers: hokein, aaron.ballman, JonasToth. hwright added a project: clang-tools-extra. Herald added subscribers: cfe-commits, xazax.hun, mgorny. This is an analog to the existing `abseil-duration-subtraction` check. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D57185 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationAdditionCheck.cpp clang-tidy/abseil/DurationAdditionCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-addition.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-addition.cpp Index: test/clang-tidy/abseil-duration-addition.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-addition.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s abseil-duration-addition %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Time t; + int i; + + i = absl::ToUnixHours(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(t + absl::Hours(5)) + i = absl::ToUnixMinutes(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(t + absl::Minutes(5)) + i = absl::ToUnixSeconds(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + i = absl::ToUnixMillis(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(t + absl::Milliseconds(5)) + i = absl::ToUnixMicros(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Microseconds(5)) + i = absl::ToUnixNanos(t) + 5; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(t + absl::Nanoseconds(5)) + + i = 3 + absl::ToUnixHours(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixHours(absl::Hours(3) + t) + i = 3 + absl::ToUnixMinutes(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMinutes(absl::Minutes(3) + t) + i = 3 + absl::ToUnixSeconds(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(absl::Seconds(3) + t) + i = 3 + absl::ToUnixMillis(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMillis(absl::Milliseconds(3) + t) + i = 3 + absl::ToUnixMicros(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(absl::Microseconds(3) + t) + i = 3 + absl::ToUnixNanos(t); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixNanos(absl::Nanoseconds(3) + t) + + // Undoing inverse conversions + i = absl::ToUnixMicros(t) + absl::ToInt64Microseconds(absl::Seconds(1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixMicros(t + absl::Seconds(1)) + + // Float folding + i = absl::ToUnixSeconds(t) + 5.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(5)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::FromUnixSeconds(30) + i = absl::ToUnixSeconds(THIRTY) + 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(THIRTY + absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToUnixSeconds(t) + 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform addition in the duration domain [abseil-duration-addition] + // CHECK-FIXES: absl::ToUnixSeconds(t + absl::Seconds(1)) + + // These should not match + i = 5 + 6; + i = absl::ToUnixSeconds(t) - 1.0; + i = absl::ToUnixSeconds(t) * 1.0; + i = absl::ToUnixSeconds(t) / 1.0; + +#define PLUS_FIVE(z) absl::ToUnixSeconds(z) + 5 + i = PLUS_FIVE(t); +#undef
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
This revision was automatically updated to reflect the committed changes. Closed by commit rL351473: [clang-tidy] Add abseil-duration-conversion-cast check (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D56532?vs=182043=182374#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 Files: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.h clang-tools-extra/trunk/docs/ReleaseNotes.rst clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-conversion-cast.rst clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst clang-tools-extra/trunk/test/clang-tidy/abseil-duration-conversion-cast.cpp Index: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp @@ -11,6 +11,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "DurationComparisonCheck.h" +#include "DurationConversionCastCheck.h" #include "DurationDivisionCheck.h" #include "DurationFactoryFloatCheck.h" #include "DurationFactoryScaleCheck.h" @@ -32,6 +33,8 @@ void addCheckFactories(ClangTidyCheckFactories ) override { CheckFactories.registerCheck( "abseil-duration-comparison"); +CheckFactories.registerCheck( +"abseil-duration-conversion-cast"); CheckFactories.registerCheck( "abseil-duration-division"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt === --- clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyAbseilModule AbseilTidyModule.cpp DurationComparisonCheck.cpp + DurationConversionCastCheck.cpp DurationDivisionCheck.cpp DurationFactoryFloatCheck.cpp DurationFactoryScaleCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.h === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.h +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.h @@ -0,0 +1,36 @@ +//===--- DurationConversionCastCheck.h - clang-tidy -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCONVERSIONCASTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCONVERSIONCASTCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace abseil { + +/// Checks for casts of ``absl::Duration`` conversion functions, and recommends +/// the right conversion function instead. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-conversion-cast.html +class DurationConversionCastCheck : public ClangTidyCheck { +public: + DurationConversionCastCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult ) override; +}; + +} // namespace abseil +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCONVERSIONCASTCHECK_H Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationConversionCastCheck.cpp @@ -0,0 +1,85 @@ +//===--- DurationConversionCastCheck.cpp - clang-tidy -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "DurationConversionCastCheck.h" +#include "DurationRewriter.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy {
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright updated this revision to Diff 182043. hwright marked 6 inline comments as done. hwright added a comment. Address reviewer comments CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationConversionCastCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-conversion-cast.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-conversion-cast.cpp Index: test/clang-tidy/abseil-duration-conversion-cast.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-conversion-cast.cpp @@ -0,0 +1,95 @@ +// RUN: %check_clang_tidy %s abseil-duration-conversion-cast %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1; + double x; + int i; + + i = static_cast(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = static_cast(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleHours(d1); + i = static_cast(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Minutes(d1); + x = static_cast(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMinutes(d1); + i = static_cast(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Seconds(d1); + x = static_cast(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleSeconds(d1); + i = static_cast(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Milliseconds(d1); + x = static_cast(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d1); + i = static_cast(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Microseconds(d1); + x = static_cast(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + i = static_cast(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Nanoseconds(d1); + x = static_cast(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d1); + + // Functional-style casts + i = int(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = float(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to a floating-piont number rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // C-style casts + i = (int) absl::ToDoubleHours(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: duration should be converted directly to an integer rather than through a type cast [abseil-duration-conversion-cast] + // CHECK-FIXES:
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:47-48 // if nothing needs to be done. - if (!IsValidMacro(Result, Binop->getLHS()) || - !IsValidMacro(Result, Binop->getRHS())) + if (!isNotInMacro(Result, Binop->getLHS()) || + !isNotInMacro(Result, Binop->getRHS())) return; aaron.ballman wrote: > I think this change (and the related removal) should be landed separately as > a NFC commit once this one lands, as it's logically separate from the new > check. I've gone ahead and done the change separately, which should clean this up. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright added a comment. Ping. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright updated this revision to Diff 181204. hwright marked an inline comment as done. hwright added a comment. Run `clang-format` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-conversion-cast.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-conversion-cast.cpp Index: test/clang-tidy/abseil-duration-conversion-cast.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-conversion-cast.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s abseil-duration-conversion-cast %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1; + double x; + int i; + + i = static_cast(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = static_cast(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleHours(d1); + i = static_cast(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Minutes(d1); + x = static_cast(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMinutes(d1); + i = static_cast(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Seconds(d1); + x = static_cast(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleSeconds(d1); + i = static_cast(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Milliseconds(d1); + x = static_cast(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d1); + i = static_cast(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Microseconds(d1); + x = static_cast(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + i = static_cast(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Nanoseconds(d1); + x = static_cast(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d1); + + // Functional-style casts + i = int(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = float(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // C-style casts + i = (int) absl::ToDoubleHours(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = (float) absl::ToInt64Microseconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // Macro handling + // We want to transform things in macro arguments +#define EXTERNAL(x) (x) + 5 + i = EXTERNAL(static_cast(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: EXTERNAL(absl::ToInt64Seconds(d1)); +#undef EXTERNAL + + // We don't want to transform this which get split across macro boundaries +#define SPLIT(x)
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright updated this revision to Diff 181125. hwright marked 5 inline comments as done. hwright added a comment. Update documentation line wrapping. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-conversion-cast.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-conversion-cast.cpp Index: test/clang-tidy/abseil-duration-conversion-cast.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-conversion-cast.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s abseil-duration-conversion-cast %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1; + double x; + int i; + + i = static_cast(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = static_cast(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleHours(d1); + i = static_cast(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Minutes(d1); + x = static_cast(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMinutes(d1); + i = static_cast(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Seconds(d1); + x = static_cast(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleSeconds(d1); + i = static_cast(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Milliseconds(d1); + x = static_cast(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d1); + i = static_cast(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Microseconds(d1); + x = static_cast(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + i = static_cast(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Nanoseconds(d1); + x = static_cast(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d1); + + // Functional-style casts + i = int(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = float(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // C-style casts + i = (int) absl::ToDoubleHours(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = (float) absl::ToInt64Microseconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // Macro handling + // We want to transform things in macro arguments +#define EXTERNAL(x) (x) + 5 + i = EXTERNAL(static_cast(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: EXTERNAL(absl::ToInt64Seconds(d1)); +#undef EXTERNAL + + // We don't want to transform this which get split across macro boundaries +#define
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright added inline comments. Comment at: docs/clang-tidy/checks/abseil-duration-conversion-cast.rst:20 + + + // Original - Cast from a double to an integer MyDeveloperDay wrote: > nit: double blank line This is intentional (and consistent with other examples in other tools). Comment at: docs/clang-tidy/checks/abseil-duration-conversion-cast.rst:28 + + +Note: In the second example, the suggested fix could yield a different result, MyDeveloperDay wrote: > nit: double blank line This is intentional (and consistent with other documentation). CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56532/new/ https://reviews.llvm.org/D56532 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56532: [clang-tidy] Add the abseil-duration-conversion-cast check
hwright created this revision. hwright added reviewers: hokein, aaron.ballman. hwright added a project: clang-tools-extra. Herald added subscribers: cfe-commits, xazax.hun, mgorny. This suggests simplifying expressions which are casting conversion functions, such as `static_cast(absl::ToDoubleSeconds(...))` Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D56532 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.cpp clang-tidy/abseil/DurationConversionCastCheck.h clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-conversion-cast.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-conversion-cast.cpp Index: test/clang-tidy/abseil-duration-conversion-cast.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-conversion-cast.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s abseil-duration-conversion-cast %t -- -- -I%S/Inputs + +#include "absl/time/time.h" + +void f() { + absl::Duration d1; + double x; + int i; + + i = static_cast(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = static_cast(absl::ToInt64Hours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleHours(d1); + i = static_cast(absl::ToDoubleMinutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Minutes(d1); + x = static_cast(absl::ToInt64Minutes(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMinutes(d1); + i = static_cast(absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Seconds(d1); + x = static_cast(absl::ToInt64Seconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleSeconds(d1); + i = static_cast(absl::ToDoubleMilliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Milliseconds(d1); + x = static_cast(absl::ToInt64Milliseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d1); + i = static_cast(absl::ToDoubleMicroseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Microseconds(d1); + x = static_cast(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + i = static_cast(absl::ToDoubleNanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Nanoseconds(d1); + x = static_cast(absl::ToInt64Nanoseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d1); + + // Functional-style casts + i = int(absl::ToDoubleHours(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = float(absl::ToInt64Microseconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // C-style casts + i = (int) absl::ToDoubleHours(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToInt64Hours(d1); + x = (float) absl::ToInt64Microseconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: convert duration directly to double [abseil-duration-conversion-cast] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d1); + + // Macro handling + // We want to transform things in macro arguments +#define EXTERNAL(x) (x) + 5 + i = EXTERNAL(static_cast(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: convert duration directly to integer [abseil-duration-conversion-cast] + // CHECK-FIXES:
[PATCH] D56090: Add a matcher for members of an initializer list expression
This revision was automatically updated to reflect the committed changes. Closed by commit rL350523: [clang] Add AST matcher for initializer list members (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D56090?vs=180248=180481#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 Files: cfe/trunk/docs/LibASTMatchersReference.html cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Index: cfe/trunk/docs/LibASTMatchersReference.html === --- cfe/trunk/docs/LibASTMatchersReference.html +++ cfe/trunk/docs/LibASTMatchersReference.html @@ -718,7 +718,7 @@ Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Stmt.html;>StmtblockExprMatcherhttps://clang.llvm.org/doxygen/classclang_1_1BlockExpr.html;>BlockExpr... -MAtches a reference to a block. +Matches a reference to a block. Example: matches "^{}": void f() { ^{}(); } @@ -5866,6 +5866,15 @@ +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasInitunsigned N, ast_matchers::Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher +Matches the n'th item of an initializer list expression. + +Example matches y. +(matcher = initListExpr(hasInit(0, expr( + int x{y}. + + + Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasSyntacticFormMatcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher Matches the syntactic form of init list expressions (if expression have it). Index: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h === --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,19 @@ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N), Finder, Builder); +} + /// Matches declaration statements that contain a specific number of /// declarations. /// Index: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp === --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp @@ -273,6 +273,7 @@ REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); Index: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp === --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2255,6 +2255,18 @@ notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( +matches("int x{0};", +initListExpr(hasInit(0, expr(); + EXPECT_FALSE( +matches("int x{0};", +initListExpr(hasInit(1, expr(); + EXPECT_FALSE( +matches("int x;", +initListExpr(hasInit(0, expr(); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain(; Index: cfe/trunk/docs/LibASTMatchersReference.html === --- cfe/trunk/docs/LibASTMatchersReference.html +++ cfe/trunk/docs/LibASTMatchersReference.html @@ -718,7 +718,7 @@ Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Stmt.html;>StmtblockExprMatcherhttps://clang.llvm.org/doxygen/classclang_1_1BlockExpr.html;>BlockExpr... -MAtches a reference to a block. +Matches a reference to a block. Example: matches "^{}": void f() { ^{}(); } @@ -5866,6 +5866,15 @@ +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasInitunsigned N, ast_matchers::Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher +Matches the n'th item of an initializer list expression. + +Example matches y. +(matcher = initListExpr(hasInit(0, expr( + int x{y}. + + + Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasSyntacticFormMatcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher Matches
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright marked 4 inline comments as done. hwright added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3527 + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); klimek wrote: > aaron.ballman wrote: > > hwright wrote: > > > aaron.ballman wrote: > > > > I'm not certain we want the `IgnoreParenImpCasts()` here -- what if > > > > someone wants to match an initializer that uses one of those properties? > > > The `hasArg` implementation directly above has the same call to > > > `IgnoreParenImpCasts()`. Is it also in error? (It would seem that they > > > should both be consistent.) > > Yeah, I noticed that as well. Doing some code archaeology, it seems that > > `hasArg()` has had that form since its inception and it was never > > explicitly discussed what should happen there. > > > > @klimek -- do you have opinions here, since you wrote the original code for > > `hasArg()`? Should we be leaving the paren and implicit cast stripping up > > to the caller rather than doing it automatically? > Sigh, yea, this is one of those hard decisions: in the end, we decided that > the downside of surprise of users not seeing what they expected (due to an > imp cast) was less bad than basically taking away the ability to match imp > casts, so we stopped putting ignoreparenimpcasts everywhere. I'm not entirely > sure how to rate consistency with hasArg vs. getting us towards a more > explicit world, but my gut would probably go with leaving the > ignoreparenimpcasts out and see how bad people find it. Removed the call to `IgnoreParenImpCasts()`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright updated this revision to Diff 180248. hwright added a comment. Removed `IgnoreParenImpCasts` call. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 Files: docs/LibASTMatchersReference.html include/clang/ASTMatchers/ASTMatchers.h lib/ASTMatchers/Dynamic/Registry.cpp unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp === --- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2255,6 +2255,18 @@ notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( +matches("int x{0};", +initListExpr(hasInit(0, expr(); + EXPECT_FALSE( +matches("int x{0};", +initListExpr(hasInit(1, expr(); + EXPECT_FALSE( +matches("int x;", +initListExpr(hasInit(0, expr(); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain(; Index: lib/ASTMatchers/Dynamic/Registry.cpp === --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -273,6 +273,7 @@ REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,19 @@ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N), Finder, Builder); +} + /// Matches declaration statements that contain a specific number of /// declarations. /// Index: docs/LibASTMatchersReference.html === --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -718,7 +718,7 @@ Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Stmt.html;>StmtblockExprMatcherhttps://clang.llvm.org/doxygen/classclang_1_1BlockExpr.html;>BlockExpr... -MAtches a reference to a block. +Matches a reference to a block. Example: matches "^{}": void f() { ^{}(); } @@ -5866,6 +5866,15 @@ +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasInitunsigned N, ast_matchers::Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher +Matches the n'th item of an initializer list expression. + +Example matches y. +(matcher = initListExpr(hasInit(0, expr( + int x{y}. + + + Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasSyntacticFormMatcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher Matches the syntactic form of init list expressions (if expression have it). Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp === --- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2255,6 +2255,18 @@ notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( +matches("int x{0};", +initListExpr(hasInit(0, expr(); + EXPECT_FALSE( +matches("int x{0};", +initListExpr(hasInit(1, expr(); + EXPECT_FALSE( +matches("int x;", +initListExpr(hasInit(0, expr(); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain(; Index: lib/ASTMatchers/Dynamic/Registry.cpp === --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -273,6 +273,7 @@ REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,19 @@
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3527 + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); aaron.ballman wrote: > I'm not certain we want the `IgnoreParenImpCasts()` here -- what if someone > wants to match an initializer that uses one of those properties? The `hasArg` implementation directly above has the same call to `IgnoreParenImpCasts()`. Is it also in error? (It would seem that they should both be consistent.) CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright updated this revision to Diff 180089. hwright marked an inline comment as done. hwright added a comment. Added tests, update docs. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 Files: docs/LibASTMatchersReference.html include/clang/ASTMatchers/ASTMatchers.h lib/ASTMatchers/Dynamic/Registry.cpp unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp === --- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2255,6 +2255,18 @@ notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( +matches("int x{0};", +initListExpr(hasInit(0, expr(); + EXPECT_FALSE( +matches("int x{0};", +initListExpr(hasInit(1, expr(); + EXPECT_FALSE( +matches("int x;", +initListExpr(hasInit(0, expr(); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain(; Index: lib/ASTMatchers/Dynamic/Registry.cpp === --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -273,6 +273,7 @@ REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,20 @@ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); +} + /// Matches declaration statements that contain a specific number of /// declarations. /// Index: docs/LibASTMatchersReference.html === --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -718,7 +718,7 @@ Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Stmt.html;>StmtblockExprMatcherhttps://clang.llvm.org/doxygen/classclang_1_1BlockExpr.html;>BlockExpr... -MAtches a reference to a block. +Matches a reference to a block. Example: matches "^{}": void f() { ^{}(); } @@ -5866,6 +5866,15 @@ +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasInitunsigned N, ast_matchers::Matcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher +Matches the n'th item of an initializer list expression. + +Example matches y. +(matcher = initListExpr(hasInit(0, expr( + int x{y}. + + + Matcherhttps://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html;>InitListExprhasSyntacticFormMatcherhttps://clang.llvm.org/doxygen/classclang_1_1Expr.html;>Expr InnerMatcher Matches the syntactic form of init list expressions (if expression have it). Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp === --- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2255,6 +2255,18 @@ notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( +matches("int x{0};", +initListExpr(hasInit(0, expr(); + EXPECT_FALSE( +matches("int x{0};", +initListExpr(hasInit(1, expr(); + EXPECT_FALSE( +matches("int x;", +initListExpr(hasInit(0, expr(); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain(; Index: lib/ASTMatchers/Dynamic/Registry.cpp === --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -273,6 +273,7 @@ REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); + REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright added a comment. @lebedev.ri Where do the appropriate tests live? (I couldn't find an obvious subdirectory in `test/`) Where are the instructions for regenerating the documentation? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56090/new/ https://reviews.llvm.org/D56090 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56090: Add a matcher for members of an initializer list expression
hwright created this revision. hwright added a reviewer: aaron.ballman. hwright added a project: clang. Herald added a subscriber: cfe-commits. Much like `hasArg` for various call expressions, this allows `LibTooling` users to match against a member of an initializer list. This is currently being used as part of the `abseil-duration-scale` clang-tidy check. Repository: rC Clang https://reviews.llvm.org/D56090 Files: include/clang/ASTMatchers/ASTMatchers.h Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,20 @@ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); +} + /// Matches declaration statements that contain a specific number of /// declarations. /// Index: include/clang/ASTMatchers/ASTMatchers.h === --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3514,6 +3514,20 @@ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); +} + /// Matches declaration statements that contain a specific number of /// declarations. /// ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56012: [clang-tidy] Be more liberal about literal zeroes in abseil checks
This revision was automatically updated to reflect the committed changes. Closed by commit rL349953: [clang-tidy] Be more liberal about literal zeroes in abseil checks (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D56012?vs=179335=179341#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56012/new/ https://reviews.llvm.org/D56012 Files: clang-tools-extra/trunk/clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp clang-tools-extra/trunk/test/clang-tidy/abseil-duration-factory-scale.cpp Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp @@ -105,14 +105,44 @@ llvm_unreachable("unknown scaling factor"); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); +} + /// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult , const Expr ) { - return selectFirst( - "val", - match(expr(ignoringImpCasts(anyOf(integerLiteral(equals(0)), - floatLiteral(equals(0.0) - .bind("val"), - Node, *Result.Context)) != nullptr; + auto ZeroMatcher = + anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0))); + + // Check to see if we're using a zero directly. + if (selectFirst( + "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node, + *Result.Context)) != nullptr) +return true; + + // Now check to see if we're using a functional cast with a scalar + // initializer expression, e.g. `int{0}`. + if (selectFirst( + "val", + match(cxxFunctionalCastExpr( +hasDestinationType( +anyOf(isInteger(), realFloatingPointType())), +hasSourceExpression(initListExpr(hasInit(0, ZeroMatcher +.bind("val"), +Node, *Result.Context)) != nullptr) +return true; + + return false; } llvm::Optional Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationFactoryScaleCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationFactoryScaleCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationFactoryScaleCheck.cpp @@ -123,6 +123,10 @@ hasArgument( 0, ignoringImpCasts(anyOf( + cxxFunctionalCastExpr( + hasDestinationType( + anyOf(isInteger(), realFloatingPointType())), + hasSourceExpression(initListExpr())), integerLiteral(equals(0)), floatLiteral(equals(0.0)), binaryOperator(hasOperatorName("*"), hasEitherOperand(ignoringImpCasts( Index: clang-tools-extra/trunk/test/clang-tidy/abseil-duration-factory-scale.cpp === --- clang-tools-extra/trunk/test/clang-tidy/abseil-duration-factory-scale.cpp +++ clang-tools-extra/trunk/test/clang-tidy/abseil-duration-factory-scale.cpp @@ -2,6 +2,9 @@ #include "absl/time/time.h" +namespace std { typedef long long int64_t; } +using int64_t = std::int64_t; + void ScaleTest() { absl::Duration d; @@ -30,6 +33,15 @@ d = absl::Seconds(0x0.01p-126f); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int64_t{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(float{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); // Fold seconds into minutes d = absl::Seconds(30 * 60); @@ -83,6 +95,8 @@ // None of
[PATCH] D56012: [clang-tidy] Be more liberal about literal zeroes in abseil checks
hwright added a comment. btw, I think `hasInit` should probably be moved into the core set of matchers at some point. Comment at: clang-tidy/abseil/DurationRewriter.cpp:110 + ast_matchers::internal::Matcher, InnerMatcher) { + return (N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, aaron.ballman wrote: > Spurious parens can be removed. Done. (Though there are similar parens in the implementation of `hasArgument`. :) Comment at: test/clang-tidy/abseil-duration-factory-scale.cpp:34 // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] aaron.ballman wrote: > Do you also have users doing something like: `absl::Seconds(int{});`? I have not yet seen that. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56012/new/ https://reviews.llvm.org/D56012 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56012: [clang-tidy] Be more liberal about literal zeroes in abseil checks
hwright updated this revision to Diff 179335. hwright marked 6 inline comments as done. hwright added a comment. Add documentation, adjust test. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D56012/new/ https://reviews.llvm.org/D56012 Files: clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp test/clang-tidy/abseil-duration-factory-scale.cpp Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -2,6 +2,9 @@ #include "absl/time/time.h" +namespace std { typedef long long int64_t; } +using int64_t = std::int64_t; + void ScaleTest() { absl::Duration d; @@ -30,6 +33,15 @@ d = absl::Seconds(0x0.01p-126f); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int64_t{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(float{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); // Fold seconds into minutes d = absl::Seconds(30 * 60); @@ -83,6 +95,8 @@ // None of these should trigger the check d = absl::Seconds(60); + d = absl::Seconds(int{60}); + d = absl::Seconds(float{60}); d = absl::Seconds(60 + 30); d = absl::Seconds(60 - 30); d = absl::Seconds(50 * 30); Index: clang-tidy/abseil/DurationRewriter.cpp === --- clang-tidy/abseil/DurationRewriter.cpp +++ clang-tidy/abseil/DurationRewriter.cpp @@ -105,14 +105,44 @@ llvm_unreachable("unknown scaling factor"); } +/// Matches the n'th item of an initializer list expression. +/// +/// Example matches y. +/// (matcher = initListExpr(hasInit(0, expr( +/// \code +/// int x{y}. +/// \endcode +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder); +} + /// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult , const Expr ) { - return selectFirst( - "val", - match(expr(ignoringImpCasts(anyOf(integerLiteral(equals(0)), - floatLiteral(equals(0.0) - .bind("val"), - Node, *Result.Context)) != nullptr; + auto ZeroMatcher = + anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0))); + + // Check to see if we're using a zero directly. + if (selectFirst( + "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node, + *Result.Context)) != nullptr) +return true; + + // Now check to see if we're using a functional cast with a scalar + // initializer expression, e.g. `int{0}`. + if (selectFirst( + "val", + match(cxxFunctionalCastExpr( +hasDestinationType( +anyOf(isInteger(), realFloatingPointType())), +hasSourceExpression(initListExpr(hasInit(0, ZeroMatcher +.bind("val"), +Node, *Result.Context)) != nullptr) +return true; + + return false; } llvm::Optional Index: clang-tidy/abseil/DurationFactoryScaleCheck.cpp === --- clang-tidy/abseil/DurationFactoryScaleCheck.cpp +++ clang-tidy/abseil/DurationFactoryScaleCheck.cpp @@ -123,6 +123,10 @@ hasArgument( 0, ignoringImpCasts(anyOf( + cxxFunctionalCastExpr( + hasDestinationType( + anyOf(isInteger(), realFloatingPointType())), + hasSourceExpression(initListExpr())), integerLiteral(equals(0)), floatLiteral(equals(0.0)), binaryOperator(hasOperatorName("*"), hasEitherOperand(ignoringImpCasts( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D56012: Be more liberal about literal zeroes in abseil checks
hwright created this revision. hwright added reviewers: aaron.ballman, JonasToth, alexfh, hokein. hwright added a project: clang-tools-extra. Herald added a subscriber: cfe-commits. Previously, we'd only match on literal floating or integral zeroes, but I've now also learned that some users spell that value as `int{0}` or `float{0}`, which also need to be matched. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D56012 Files: clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp test/clang-tidy/abseil-duration-factory-scale.cpp Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,5 +1,6 @@ // RUN: %check_clang_tidy %s abseil-duration-factory-scale %t -- -- -I%S/Inputs +#include #include "absl/time/time.h" void ScaleTest() { @@ -30,6 +31,15 @@ d = absl::Seconds(0x0.01p-126f); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(int64_t{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(float{0}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); // Fold seconds into minutes d = absl::Seconds(30 * 60); @@ -83,6 +93,8 @@ // None of these should trigger the check d = absl::Seconds(60); + d = absl::Seconds(int{60}); + d = absl::Seconds(float{60}); d = absl::Seconds(60 + 30); d = absl::Seconds(60 - 30); d = absl::Seconds(50 * 30); Index: clang-tidy/abseil/DurationRewriter.cpp === --- clang-tidy/abseil/DurationRewriter.cpp +++ clang-tidy/abseil/DurationRewriter.cpp @@ -105,14 +105,37 @@ llvm_unreachable("unknown scaling factor"); } +AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, + ast_matchers::internal::Matcher, InnerMatcher) { + return (N < Node.getNumInits() && + InnerMatcher.matches(*Node.getInit(N)->IgnoreParenImpCasts(), Finder, + Builder)); +} + /// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult , const Expr ) { - return selectFirst( - "val", - match(expr(ignoringImpCasts(anyOf(integerLiteral(equals(0)), - floatLiteral(equals(0.0) - .bind("val"), - Node, *Result.Context)) != nullptr; + auto ZeroMatcher = + anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0))); + + // Check to see if we're using a zero directly. + if (selectFirst( + "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node, + *Result.Context)) != nullptr) +return true; + + // Now check to see if we're using a functional cast with a scalar + // initializer expression, e.g. `int{0}`. + if (selectFirst( + "val", + match(cxxFunctionalCastExpr( +hasDestinationType( +anyOf(isInteger(), realFloatingPointType())), +hasSourceExpression(initListExpr(hasInit(0, ZeroMatcher +.bind("val"), +Node, *Result.Context)) != nullptr) +return true; + + return false; } llvm::Optional Index: clang-tidy/abseil/DurationFactoryScaleCheck.cpp === --- clang-tidy/abseil/DurationFactoryScaleCheck.cpp +++ clang-tidy/abseil/DurationFactoryScaleCheck.cpp @@ -123,6 +123,10 @@ hasArgument( 0, ignoringImpCasts(anyOf( + cxxFunctionalCastExpr( + hasDestinationType( + anyOf(isInteger(), realFloatingPointType())), + hasSourceExpression(initListExpr())), integerLiteral(equals(0)), floatLiteral(equals(0.0)), binaryOperator(hasOperatorName("*"), hasEitherOperand(ignoringImpCasts( Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,5 +1,6 @@ // RUN:
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
This revision was automatically updated to reflect the committed changes. hwright marked an inline comment as done. Closed by commit rL349636: [clang-tidy] Diagnose abseil-duration-comparison on macro arguments (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D55784?vs=178733=178891#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 Files: clang-tools-extra/trunk/clang-tidy/abseil/DurationComparisonCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h clang-tools-extra/trunk/clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tools-extra/trunk/test/clang-tidy/abseil-duration-comparison.cpp Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h @@ -65,7 +65,7 @@ /// Assuming `Node` has type `double` or `int` representing a time interval of /// `Scale`, return the expression to make it a suitable `Duration`. -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node); Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationComparisonCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationComparisonCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationComparisonCheck.cpp @@ -19,6 +19,26 @@ namespace tidy { namespace abseil { +/// Return `true` if `E` is a either: not a macro at all; or an argument to +/// one. In the latter case, we should still transform it. +static bool IsValidMacro(const MatchFinder::MatchResult , + const Expr *E) { + if (!E->getBeginLoc().isMacroID()) +return true; + + SourceLocation Loc = E->getBeginLoc(); + // We want to get closer towards the initial macro typed into the source only + // if the location is being expanded as a macro argument. + while (Result.SourceManager->isMacroArgExpansion(Loc)) { +// We are calling getImmediateMacroCallerLoc, but note it is essentially +// equivalent to calling getImmediateSpellingLoc in this context according +// to Clang implementation. We are not calling getImmediateSpellingLoc +// because Clang comment says it "should not generally be used by clients." +Loc = Result.SourceManager->getImmediateMacroCallerLoc(Loc); + } + return !Loc.isMacroID(); +} + void DurationComparisonCheck::registerMatchers(MatchFinder *Finder) { auto Matcher = binaryOperator(anyOf(hasOperatorName(">"), hasOperatorName(">="), @@ -35,10 +55,6 @@ void DurationComparisonCheck::check(const MatchFinder::MatchResult ) { const auto *Binop = Result.Nodes.getNodeAs("binop"); - // Don't try to replace things inside of macro definitions. - if (Binop->getExprLoc().isMacroID()) -return; - llvm::Optional Scale = getScaleForInverse( Result.Nodes.getNodeAs("function_decl")->getName()); if (!Scale) @@ -48,19 +64,19 @@ // want to handle the case of rewriting both sides. This is much simpler if // we unconditionally try and rewrite both, and let the rewriter determine // if nothing needs to be done. - llvm::Optional LhsReplacement = + if (!IsValidMacro(Result, Binop->getLHS()) || + !IsValidMacro(Result, Binop->getRHS())) +return; + std::string LhsReplacement = rewriteExprFromNumberToDuration(Result, *Scale, Binop->getLHS()); - llvm::Optional RhsReplacement = + std::string RhsReplacement = rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS()); - if (!(LhsReplacement && RhsReplacement)) -return; - diag(Binop->getBeginLoc(), "perform comparison in the duration domain") << FixItHint::CreateReplacement(Binop->getSourceRange(), - (llvm::Twine(*LhsReplacement) + " " + + (llvm::Twine(LhsReplacement) + " " + Binop->getOpcodeStr() + " " + - *RhsReplacement) + RhsReplacement) .str()); } Index: clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp === --- clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp +++ clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp @@ -183,14 +183,11 @@ return ScaleIter->second; } -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
hwright marked 2 inline comments as done. hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-comparison.cpp:146 +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e, type) (v ? VALUE_IF_2(absl::To##type##Seconds(e)) : 0) + int a3 = VALUE_IF(1, d1, Double); aaron.ballman wrote: > hwright wrote: > > aaron.ballman wrote: > > > What if this is changed to: > > > ``` > > > #define VALUE_IF(v, e, type) (v ? (5 > > > > VALUE_IF_2(absl::To##type##Seconds(e))) : 0) > > > ``` > > This also doesn't transform. > Fantastic, thank you! I wouldn't expect a fix-it there due to the macro > shenanigans, but I'm surprised it does not diagnose given that it expands to > basically the same thing as `a` and `a2` above: https://godbolt.org/z/D1MvGX > (ignore the errors but look at the macro expansion from the diagnostics). > > Granted, this situation is uncommon enough, so feel free to add a FIXME > comment to the `a4` test case to say that it probably should be diagnosed > without a fix-it hint (assuming you agree). I actually prefer not to diagnose here, mostly because I'm not sure what value we'd actually give without a fix-it hint. "You are holding it wrong, but we can't tell you how to hold it right." Ultimately, though, I think you are right that the number of cases this occurs are vanishingly small, and I'd expect folks doing these kinds of craziness to know what they are doing (and take responsibility thereof). Perhaps that's optimistic. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
hwright added a comment. @aaron.ballman I am both grateful and sad that I don't possess the same macro creativity as you do. :) (I'm also sad that the various clang APIs aren't as well documented as I hoped. The current solution works well, but it took a while and a bit of consultation with some other llvm'ers to get it right.) Comment at: test/clang-tidy/abseil-duration-comparison.cpp:146 +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e, type) (v ? VALUE_IF_2(absl::To##type##Seconds(e)) : 0) + int a3 = VALUE_IF(1, d1, Double); aaron.ballman wrote: > What if this is changed to: > ``` > #define VALUE_IF(v, e, type) (v ? (5 > > VALUE_IF_2(absl::To##type##Seconds(e))) : 0) > ``` This also doesn't transform. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
hwright updated this revision to Diff 178733. hwright marked 3 inline comments as done. hwright added a comment. Another test. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 Files: clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- test/clang-tidy/abseil-duration-comparison.cpp +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -127,6 +127,33 @@ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] // CHECK-FIXES: absl::Milliseconds((y + 5) * 10) > d1; + // We should still transform the expression inside this macro invocation +#define VALUE_IF(v, e) v ? (e) : 0 + int a = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: VALUE_IF(1, absl::Seconds(5) > d1); +#undef VALUE_IF + +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e) v ? VALUE_IF_2(e) : VALUE_IF_2(0) + int a2 = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:24: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: VALUE_IF(1, absl::Seconds(5) > d1); +#undef VALUE_IF +#undef VALUE_IF_2 + +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e, type) (v ? VALUE_IF_2(absl::To##type##Seconds(e)) : 0) + int a3 = VALUE_IF(1, d1, Double); +#undef VALUE_IF +#undef VALUE_IF_2 + +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e, type) (v ? (5 > VALUE_IF_2(absl::To##type##Seconds(e))) : 0) + int a4 = VALUE_IF(1, d1, Double); +#undef VALUE_IF +#undef VALUE_IF_2 + // These should not match b = 6 < 4; Index: clang-tidy/abseil/DurationSubtractionCheck.cpp === --- clang-tidy/abseil/DurationSubtractionCheck.cpp +++ clang-tidy/abseil/DurationSubtractionCheck.cpp @@ -42,10 +42,8 @@ if (!Scale) return; - llvm::Optional RhsReplacement = + std::string RhsReplacement = rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS()); - if (!RhsReplacement) -return; const Expr *LhsArg = Result.Nodes.getNodeAs("lhs_arg"); @@ -54,7 +52,7 @@ Binop->getSourceRange(), (llvm::Twine("absl::") + FuncDecl->getName() + "(" + tooling::fixit::getText(*LhsArg, *Result.Context) + " - " + - *RhsReplacement + ")") + RhsReplacement + ")") .str()); } Index: clang-tidy/abseil/DurationRewriter.h === --- clang-tidy/abseil/DurationRewriter.h +++ clang-tidy/abseil/DurationRewriter.h @@ -65,7 +65,7 @@ /// Assuming `Node` has type `double` or `int` representing a time interval of /// `Scale`, return the expression to make it a suitable `Duration`. -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node); Index: clang-tidy/abseil/DurationRewriter.cpp === --- clang-tidy/abseil/DurationRewriter.cpp +++ clang-tidy/abseil/DurationRewriter.cpp @@ -183,14 +183,11 @@ return ScaleIter->second; } -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node) { const Expr = *Node->IgnoreParenImpCasts(); - if (RootNode.getBeginLoc().isMacroID()) -return llvm::None; - // First check to see if we can undo a complimentary function call. if (llvm::Optional MaybeRewrite = rewriteInverseDurationCall(Result, Scale, RootNode)) Index: clang-tidy/abseil/DurationComparisonCheck.cpp === --- clang-tidy/abseil/DurationComparisonCheck.cpp +++ clang-tidy/abseil/DurationComparisonCheck.cpp @@ -19,6 +19,26 @@ namespace tidy { namespace abseil { +/// Return `true` if `E` is a either: not a macro at all; or an argument to +/// one. In the latter case, we should still transform it. +static bool IsValidMacro(const MatchFinder::MatchResult , + const Expr *E) { + if (!E->getBeginLoc().isMacroID()) +return true; + + SourceLocation Loc = E->getBeginLoc(); + // We want to get closer towards the initial macro typed into the source only + // if the location is being expanded as a macro argument. + while (Result.SourceManager->isMacroArgExpansion(Loc)) { +// We are calling getImmediateMacroCallerLoc,
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-comparison.cpp:131 + // We should still transform the expression inside this macro invocation +#define VALUE_IF(v, e) v ? (e) : 0 + int a = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); aaron.ballman wrote: > Can you add another example that has one more level of macro arg expansion? > e.g., > ``` > #define VALUE_IF_2(e) (e) > #define VALUE_IF(v, e) v ? VALUE_IF_2(e) : VALUE_IF_2(0) > int a = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); > ``` > Which makes me wonder -- is this transformation valid in all cases? For > instance, how do the fixes look with this abomination? > ``` > #define VALUE_IF_2(e) (e) > #define VALUE_IF(v, e, type) (v ? VALUE_IF_2(absl::To##type##Seconds(e)) : 0) > int a = VALUE_IF(1, d1, Double); > ``` > I would expect these shenanigans to be vanishingly rare, so if this turns out > to be a bad FIXIT you may want to document it as a known deficiency if you > don't feel like handling such a case. I've added both these as test cases. The first one works as expected, and I'm pleasantly surprised to see that the second one does as well (which is to say that it doesn't transform). CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55784: [clang-tidy] Update abseil-duration-comparison to handle macro arguments
hwright updated this revision to Diff 178680. hwright marked 4 inline comments as done. hwright added a comment. Update tests CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55784/new/ https://reviews.llvm.org/D55784 Files: clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- test/clang-tidy/abseil-duration-comparison.cpp +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -127,6 +127,27 @@ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] // CHECK-FIXES: absl::Milliseconds((y + 5) * 10) > d1; + // We should still transform the expression inside this macro invocation +#define VALUE_IF(v, e) v ? (e) : 0 + int a = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: VALUE_IF(1, absl::Seconds(5) > d1); +#undef VALUE_IF + +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e) v ? VALUE_IF_2(e) : VALUE_IF_2(0) + int a2 = VALUE_IF(1, 5 > absl::ToDoubleSeconds(d1)); + // CHECK-MESSAGES: [[@LINE-1]]:24: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: VALUE_IF(1, absl::Seconds(5) > d1); +#undef VALUE_IF +#undef VALUE_IF_2 + +#define VALUE_IF_2(e) (e) +#define VALUE_IF(v, e, type) (v ? VALUE_IF_2(absl::To##type##Seconds(e)) : 0) + int a3 = VALUE_IF(1, d1, Double); +#undef VALUE_IF +#undef VALUE_IF_2 + // These should not match b = 6 < 4; Index: clang-tidy/abseil/DurationSubtractionCheck.cpp === --- clang-tidy/abseil/DurationSubtractionCheck.cpp +++ clang-tidy/abseil/DurationSubtractionCheck.cpp @@ -42,10 +42,8 @@ if (!Scale) return; - llvm::Optional RhsReplacement = + std::string RhsReplacement = rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS()); - if (!RhsReplacement) -return; const Expr *LhsArg = Result.Nodes.getNodeAs("lhs_arg"); @@ -54,7 +52,7 @@ Binop->getSourceRange(), (llvm::Twine("absl::") + FuncDecl->getName() + "(" + tooling::fixit::getText(*LhsArg, *Result.Context) + " - " + - *RhsReplacement + ")") + RhsReplacement + ")") .str()); } Index: clang-tidy/abseil/DurationRewriter.h === --- clang-tidy/abseil/DurationRewriter.h +++ clang-tidy/abseil/DurationRewriter.h @@ -65,7 +65,7 @@ /// Assuming `Node` has type `double` or `int` representing a time interval of /// `Scale`, return the expression to make it a suitable `Duration`. -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node); Index: clang-tidy/abseil/DurationRewriter.cpp === --- clang-tidy/abseil/DurationRewriter.cpp +++ clang-tidy/abseil/DurationRewriter.cpp @@ -183,14 +183,11 @@ return ScaleIter->second; } -llvm::Optional rewriteExprFromNumberToDuration( +std::string rewriteExprFromNumberToDuration( const ast_matchers::MatchFinder::MatchResult , DurationScale Scale, const Expr *Node) { const Expr = *Node->IgnoreParenImpCasts(); - if (RootNode.getBeginLoc().isMacroID()) -return llvm::None; - // First check to see if we can undo a complimentary function call. if (llvm::Optional MaybeRewrite = rewriteInverseDurationCall(Result, Scale, RootNode)) Index: clang-tidy/abseil/DurationComparisonCheck.cpp === --- clang-tidy/abseil/DurationComparisonCheck.cpp +++ clang-tidy/abseil/DurationComparisonCheck.cpp @@ -19,6 +19,26 @@ namespace tidy { namespace abseil { +/// Return `true` if `E` is a either: not a macro at all; or an argument to +/// one. In the latter case, we should still transform it. +static bool IsValidMacro(const MatchFinder::MatchResult , + const Expr *E) { + if (!E->getBeginLoc().isMacroID()) +return true; + + SourceLocation Loc = E->getBeginLoc(); + // We want to get closer towards the initial macro typed into the source only + // if the location is being expanded as a macro argument. + while (Result.SourceManager->isMacroArgExpansion(Loc)) { +// We are calling getImmediateMacroCallerLoc, but note it is essentially +// equivalent to calling getImmediateSpellingLoc in this context according +// to Clang implementation. We are not calling getImmediateSpellingLoc +
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
This revision was automatically updated to reflect the committed changes. Closed by commit rL349073: [clang-tidy] Add the abseil-duration-subtraction check (authored by hwright, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D55245?vs=178039=178101#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tools-extra/trunk/clang-tidy/abseil/AbseilTidyModule.cpp clang-tools-extra/trunk/clang-tidy/abseil/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/abseil/DurationComparisonCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationRewriter.h clang-tools-extra/trunk/clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tools-extra/trunk/clang-tidy/abseil/DurationSubtractionCheck.h clang-tools-extra/trunk/docs/ReleaseNotes.rst clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-subtraction.rst clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst clang-tools-extra/trunk/test/clang-tidy/abseil-duration-subtraction.cpp Index: clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-subtraction.rst === --- clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-subtraction.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/abseil-duration-subtraction.rst @@ -0,0 +1,36 @@ +.. title:: clang-tidy - 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 +explicit. + +Examples: + +.. code-block:: c++ + + // 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)); + + + // 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); + +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 occurences 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 +overlaps. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst === --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-division abseil-duration-factory-float abseil-duration-factory-scale + abseil-duration-subtraction abseil-faster-strsplit-delimiter abseil-no-internal-dependencies abseil-no-namespace Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst === --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -93,6 +93,12 @@ Checks for cases where arguments to ``absl::Duration`` factory functions are scaled internally and could be changed to a different factory function. +- New :doc:`abseil-duration-subtraction + ` check. + + Checks for cases where subtraction should be performed in the + ``absl::Duration`` domain. + - New :doc:`abseil-faster-strsplit-delimiter ` check. Index: clang-tools-extra/trunk/test/clang-tidy/abseil-duration-subtraction.cpp === --- clang-tools-extra/trunk/test/clang-tidy/abseil-duration-subtraction.cpp +++ clang-tools-extra/trunk/test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,64 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1, d2; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning:
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added a comment. Thanks for reviewing, I'll go ahead and commit. I've also removed the hash specialization, since we moved to `llvm::IndexedMap` instead of `std::unordered_map` inside of `getInverseForScale`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright marked an inline comment as done. hwright added a comment. I've updated the documentation, and the rebased to `master`. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 178039. hwright marked an inline comment as done. hwright added a comment. Rebase and update documentation CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,64 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1, d2; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // A nested occurance + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(5)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(5)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1))) + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: docs/clang-tidy/checks/list.rst === --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-division abseil-duration-factory-float abseil-duration-factory-scale + abseil-duration-subtraction abseil-faster-strsplit-delimiter abseil-no-internal-dependencies abseil-no-namespace Index: docs/clang-tidy/checks/abseil-duration-subtraction.rst === --- /dev/null +++
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright marked 2 inline comments as done. hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-subtraction.cpp:12 + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > hwright wrote: > > > > JonasToth wrote: > > > > > From this example starting: > > > > > > > > > > - The RHS should be a nested expression with function calls, as the > > > > > RHS is transformed to create the adversary example i mean in the > > > > > transformation function above. > > > > > > > > > > ``` > > > > > absl::ToDoubleSeconds(d) - > > > > > absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) - > > > > > absl::ToDoubleSeconds(d1)); > > > > > ``` > > > > > I think you need the proper conversion function, as the result of the > > > > > expression is `double` and you need a `Duration`, right? > > > > > > > > > > But in principle starting from this idea the transformation might > > > > > break. > > > > I think there may be some confusion here (and that's entirely my fault. > > > > :) ) > > > > > > > > We should never get this expression as input to the check, since it > > > > doesn't compile (as you point out): > > > > ``` > > > > absl::ToDoubleSeconds(d) - > > > > absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) - > > > > absl::ToDoubleSeconds(d1)); > > > > ``` > > > > > > > > Since `absl::ToDoubleSeconds` requires that its argument is an > > > > `absl::Duration`, but the expression `absl::ToDoubleSeconds(d) - > > > > absl::ToDoubleSeconds(d1)` results in a `double`, we can't get this as > > > > input. > > > > > > > > There may be other expressions which could be input, but in practice > > > > they don't really happen. I've added a contrived example to the tests, > > > > but at some point the tests get too complex and confuse the fix > > > > matching infrastructure. > > > Your last sentence is the thing ;) Murphies Law will hit this check, too. > > > In my opinion wrong transformations are very unfortunate and should be > > > avoided if possible (in this case possible). > > > You can simply require that the expression of type double does not > > > contain any duration subtraction calls. > > > > > > This is even possible in the matcher-part of the check. > > I've written a test (which the testing infrastructure fails to handle well, > > so I haven't included it in the diff), and it produces these results: > > > > ``` > >// > >// > > - x = absl::ToDoubleSeconds(d) - (absl::ToDoubleSeconds(d1) - 5); > > + x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1) - > > 5)); > >// > >// > > - x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1) - > > 5)); > > + x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1 - > > absl::Seconds(5; > > ``` > > > > Those results are correct. There is a cosmetic issue of round tripping > > through the `double` conversion in the > > `absl::Seconds(absl::ToDoubleSeconds(...))` phrase, but untangling that is > > 1) difficult (because of order of operations issues) and thus; 2) probably > > the subject of a separate check. > > > > This is still such a rare case (as in, we've not encountered it in Google's > > codebase), that I'm not really concerned. But if it's worth it to > > explicitly exclude it from the traversal matcher, I can do that. > Can you say what the direct issue is? I would bet its the overlapping? > A note in the documentation would be ok from my side. When the conflicting > transformations are tried to be applied clang-tidy does not crash but print a > nice diagnostic and continue its life? Another example I've verified: ``` - x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(absl::ToDoubleSeconds(d1) - 5)); + x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1) - 5)); ``` This a nested case, and while `clang-tidy` finds both of them, it only applies the outer most one (presumably the one it finds first in its AST traversal): ``` note: this fix will not be applied because it overlaps with another fix ``` The new code can then be checked again to fix the internal instance. It's not possible to express this case in a test because testing infrastructure uses regular expressions, and the repeated strings in the test expectation cause it to get a bit confused. Given all the of the above, I'm unsure what content would go in the documentation which is specific to this check. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 177749. hwright marked 6 inline comments as done. hwright added a comment. Rebase CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,64 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1, d2; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // A nested occurance + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(5)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(5)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1))) + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: docs/clang-tidy/checks/list.rst === --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ abseil-duration-division abseil-duration-factory-float abseil-duration-factory-scale + abseil-duration-subtraction abseil-faster-strsplit-delimiter abseil-no-internal-dependencies abseil-no-namespace Index: docs/clang-tidy/checks/abseil-duration-subtraction.rst === --- /dev/null +++
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added inline comments. Comment at: test/clang-tidy/abseil-duration-subtraction.cpp:12 + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > From this example starting: > > > > > > - The RHS should be a nested expression with function calls, as the RHS > > > is transformed to create the adversary example i mean in the > > > transformation function above. > > > > > > ``` > > > absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) > > > - absl::ToDoubleSeconds(d1)); > > > ``` > > > I think you need the proper conversion function, as the result of the > > > expression is `double` and you need a `Duration`, right? > > > > > > But in principle starting from this idea the transformation might break. > > I think there may be some confusion here (and that's entirely my fault. :) ) > > > > We should never get this expression as input to the check, since it doesn't > > compile (as you point out): > > ``` > > absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) - > > absl::ToDoubleSeconds(d1)); > > ``` > > > > Since `absl::ToDoubleSeconds` requires that its argument is an > > `absl::Duration`, but the expression `absl::ToDoubleSeconds(d) - > > absl::ToDoubleSeconds(d1)` results in a `double`, we can't get this as > > input. > > > > There may be other expressions which could be input, but in practice they > > don't really happen. I've added a contrived example to the tests, but at > > some point the tests get too complex and confuse the fix matching > > infrastructure. > Your last sentence is the thing ;) Murphies Law will hit this check, too. In > my opinion wrong transformations are very unfortunate and should be avoided > if possible (in this case possible). > You can simply require that the expression of type double does not contain > any duration subtraction calls. > > This is even possible in the matcher-part of the check. I've written a test (which the testing infrastructure fails to handle well, so I haven't included it in the diff), and it produces these results: ``` // // - x = absl::ToDoubleSeconds(d) - (absl::ToDoubleSeconds(d1) - 5); + x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1) - 5)); // // - x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1) - 5)); + x = absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1 - absl::Seconds(5; ``` Those results are correct. There is a cosmetic issue of round tripping through the `double` conversion in the `absl::Seconds(absl::ToDoubleSeconds(...))` phrase, but untangling that is 1) difficult (because of order of operations issues) and thus; 2) probably the subject of a separate check. This is still such a rare case (as in, we've not encountered it in Google's codebase), that I'm not really concerned. But if it's worth it to explicitly exclude it from the traversal matcher, I can do that. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 177590. hwright marked 9 inline comments as done. hwright added a comment. Add tests CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-comparison.cpp test/clang-tidy/abseil-duration-factory-float.cpp test/clang-tidy/abseil-duration-factory-scale.cpp test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,64 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1, d2; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // A nested occurance + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(5)); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(5)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::Seconds(absl::ToDoubleSeconds(d1))); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(absl::ToDoubleSeconds(d1))) + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,32 +1,6 @@ -// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t +// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t -- -- -I %S/Inputs
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationRewriter.cpp:21 +struct DurationScale2IndexFunctor { + using argument_type = DurationScale; + unsigned operator()(DurationScale Scale) const { JonasToth wrote: > Are you using `argument_type`? Browser searching did only show one result. This is required by `IndexedMap`, if I understand correctly. Comment at: clang-tidy/abseil/DurationRewriter.cpp:23 + unsigned operator()(DurationScale Scale) const { +return static_cast(Scale); + } JonasToth wrote: > Why not `std::uint8_t` as its the underlying type for the `enum`? This is required by `IndexedMap`, if I understand correctly. Comment at: clang-tidy/abseil/DurationRewriter.cpp:77 + getInverseForScale(Scale); + if (const auto *MaybeCallArg = selectFirst( + "e", JonasToth wrote: > In Principle the `Node` could have multiple expressions that are a call if > there is nesting. > The transformation is correct from what I see right now, but might result in > the necessity of multiple passes for the check. (Is the addition version > affected from that too?) > > Given the recursive nature of the matcher you could construct a nesting with > the inner part being a subtraction, too. The generated fixes would conflict > and none of them would be applied. At least thats what I would expect right > now. Please take a look at this issue. There isn't an imminent addition version at this point. This matcher isn't recursive: it's just looking at the entire node to see if it is a call to the inverse function. If an inverse is embedded as part of a deeper expression, it won't see it (e.g., there no `hasDescendant` in this matcher). Comment at: test/clang-tidy/Inputs/absl/time/time.h:1 +// Mimic the implementation of absl::Duration +namespace absl { JonasToth wrote: > I think having the extraction of the common test-stuff into this header as > one commit would be better. Would you prepare such a patch? I can commit for > you. It probably makes sense if you ask for commit access > (https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access). Do as > you wish. I can do this, but it might take a bit to get the commit bit turned on. Comment at: test/clang-tidy/abseil-duration-subtraction.cpp:12 + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] JonasToth wrote: > From this example starting: > > - The RHS should be a nested expression with function calls, as the RHS is > transformed to create the adversary example i mean in the transformation > function above. > > ``` > absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) - > absl::ToDoubleSeconds(d1)); > ``` > I think you need the proper conversion function, as the result of the > expression is `double` and you need a `Duration`, right? > > But in principle starting from this idea the transformation might break. I think there may be some confusion here (and that's entirely my fault. :) ) We should never get this expression as input to the check, since it doesn't compile (as you point out): ``` absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1)); ``` Since `absl::ToDoubleSeconds` requires that its argument is an `absl::Duration`, but the expression `absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1)` results in a `double`, we can't get this as input. There may be other expressions which could be input, but in practice they don't really happen. I've added a contrived example to the tests, but at some point the tests get too complex and confuse the fix matching infrastructure. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationRewriter.cpp:20-39 +struct DurationScale2IndexFunctor { + using argument_type = DurationScale; + unsigned operator()(DurationScale Scale) const { +switch (Scale) { +case DurationScale::Hours: + return 0; +case DurationScale::Minutes: lebedev.ri wrote: > You should not need this if you change the `enum` instead. The function is still required; the switch can be removed with a `static_cast`. Comment at: clang-tidy/abseil/DurationRewriter.cpp:66-77 +InverseMap[DurationScale::Hours] = +std::make_pair("::absl::ToDoubleHours", "::absl::ToInt64Hours"); +InverseMap[DurationScale::Minutes] = +std::make_pair("::absl::ToDoubleMinutes", "::absl::ToInt64Minutes"); +InverseMap[DurationScale::Seconds] = +std::make_pair("::absl::ToDoubleSeconds", "::absl::ToInt64Seconds"); +InverseMap[DurationScale::Milliseconds] = std::make_pair( lebedev.ri wrote: > I was thinking of more like > ``` > for(std::pair e : std::initializer_list({ >{DurationScale::Hours, > std::make_pair("::absl::ToDoubleHours", "::absl::ToInt64Hours")}. >})) > InverseMap[e.first] = e.second; > ``` The compilable construction looks something like: ``` for (const auto : {std::make_pair(DurationScale::Hours, std::make_pair("::absl::ToDoubleHours", "::absl::ToInt64Hours"))}) ``` Which is a bit more verbose than just assigning values to the map (and not any more efficient), so I've just left this bit as-is. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 177509. hwright marked 5 inline comments as done. hwright added a comment. Use `static_cast` instead of a `switch` for `IndexedMap` lookup. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-comparison.cpp test/clang-tidy/abseil-duration-factory-float.cpp test/clang-tidy/abseil-duration-factory-scale.cpp test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,56 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,32 +1,6 @@ -// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t +// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t -- -- -I %S/Inputs -// Mimic the implementation of absl::Duration -namespace absl { - -class Duration {}; - -Duration Nanoseconds(long long); -Duration Microseconds(long long); -Duration Milliseconds(long long); -Duration Seconds(long long); -Duration Minutes(long long); -Duration Hours(long long); - -#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ - Duration NAME(float n); \ - Duration NAME(double n);\ - template\ - Duration NAME(T n); -
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added a comment. Reminder: I'll need somebody to submit this for me, since I don't have subversion access. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 177325. hwright marked 7 inline comments as done. hwright added a comment. Use an `IndexedMap` instead of an `std::unordered_map` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-comparison.cpp test/clang-tidy/abseil-duration-factory-float.cpp test/clang-tidy/abseil-duration-factory-scale.cpp test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,56 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,32 +1,6 @@ -// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t +// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t -- -- -I %S/Inputs -// Mimic the implementation of absl::Duration -namespace absl { - -class Duration {}; - -Duration Nanoseconds(long long); -Duration Microseconds(long long); -Duration Milliseconds(long long); -Duration Seconds(long long); -Duration Minutes(long long); -Duration Hours(long long); - -#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ - Duration NAME(float n); \ - Duration NAME(double n);\ - template\ - Duration NAME(T n); -
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationRewriter.cpp:35 +getInverseForScale(DurationScale Scale) { + static const std::unordered_map> lebedev.ri wrote: > hwright wrote: > > lebedev.ri wrote: > > > https://llvm.org/docs/ProgrammersManual.html#other-map-like-container-options > > > > We never use hash_set and unordered_set because they are generally very > > > > expensive (each insertion requires a malloc) and very non-portable. > > > > > > Since the key is an enum, [[ > > > https://llvm.org/docs/ProgrammersManual.html#llvm-adt-indexedmap-h | > > > `llvm/ADT/IndexedMap.h` ]] should be a much better fit. > > It doesn't look like `IndexedMap` has a constructor which takes an > > initializer list. Without it, this code get a bit more difficult to read, > > and I'd prefer to optimize for readability here. > The manual still 'recommends' not to use them. > Simple solution: immediately invoked lambda > Better solution: try to add such constructor to `IndexedMap`. In hopes of not making this too much of a yak shave, I've gone with the immediately invoked lambda. Comment at: clang-tidy/abseil/DurationRewriter.cpp:74 + Node, *Result.Context))) { +return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str(); + } lebedev.ri wrote: > hwright wrote: > > lebedev.ri wrote: > > > So you generate fix-it, and then immediately degrade it into a string. > > > Weird. > > This doesn't generate a fix-it, it just fetches the text of the given node > > as a `StringRef` but we're returning a `string`, so we need to convert. > > > > Is there a more canonical method I should use to fetch a node's text? > I don't know the answer, but have you tried looking what > `tooling::fixit::getText()` does internally? I have. It calls `internal::getText`, which, from the namespace, I'm hesitant to call in this context. Comment at: clang-tidy/abseil/DurationRewriter.cpp:156 +llvm::Optional getScaleForInverse(llvm::StringRef Name) { + static const llvm::DenseMap ScaleMap( + {{"ToDoubleHours", DurationScale::Hours}, lebedev.ri wrote: > Are you very sure this shouldn't be [[ > https://llvm.org/docs/ProgrammersManual.html#llvm-adt-stringmap-h | > `StringMap` ]]? Nope. Thanks for the catch! CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationRewriter.cpp:35 +getInverseForScale(DurationScale Scale) { + static const std::unordered_map> lebedev.ri wrote: > https://llvm.org/docs/ProgrammersManual.html#other-map-like-container-options > > We never use hash_set and unordered_set because they are generally very > > expensive (each insertion requires a malloc) and very non-portable. > > Since the key is an enum, [[ > https://llvm.org/docs/ProgrammersManual.html#llvm-adt-indexedmap-h | > `llvm/ADT/IndexedMap.h` ]] should be a much better fit. It doesn't look like `IndexedMap` has a constructor which takes an initializer list. Without it, this code get a bit more difficult to read, and I'd prefer to optimize for readability here. Comment at: clang-tidy/abseil/DurationRewriter.cpp:68 + getInverseForScale(Scale); + if (const Expr *MaybeCallArg = selectFirst( + "e", match(callExpr(callee(functionDecl( lebedev.ri wrote: > lebedev.ri wrote: > > `if (const auto *MaybeCallArg` > Early return? I'm not quite sure what you mean by `Early return?` Are you suggesting that the call to `selectFirst` should be pulled out of the `if` conditional, and then the inverse checked to return `llvm::None` first? Comment at: clang-tidy/abseil/DurationRewriter.cpp:74 + Node, *Result.Context))) { +return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str(); + } lebedev.ri wrote: > So you generate fix-it, and then immediately degrade it into a string. Weird. This doesn't generate a fix-it, it just fetches the text of the given node as a `StringRef` but we're returning a `string`, so we need to convert. Is there a more canonical method I should use to fetch a node's text? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 177266. hwright marked 8 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/Inputs/absl/time/time.h test/clang-tidy/abseil-duration-comparison.cpp test/clang-tidy/abseil-duration-factory-float.cpp test/clang-tidy/abseil-duration-factory-scale.cpp test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,56 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t -- -- -I %S/Inputs + +#include "absl/time/time.h" + +void f() { + double x; + absl::Duration d, d1; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(THIRTY - absl::Seconds(1)) +#undef THIRTY + + // Some other contexts + if (absl::ToDoubleSeconds(d) - 1.0 > 10) {} + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: if (absl::ToDoubleSeconds(d - absl::Seconds(1)) > 10) {} + + // These should not match + x = 5 - 6; + x = 4 - absl::ToDoubleSeconds(d) - 6.5 - 8.0; + x = absl::ToDoubleSeconds(d) + 1.0; + x = absl::ToDoubleSeconds(d) * 1.0; + x = absl::ToDoubleSeconds(d) / 1.0; + +#define MINUS_FIVE(z) absl::ToDoubleSeconds(z) - 5 + x = MINUS_FIVE(d); +#undef MINUS_FIVE +} Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- test/clang-tidy/abseil-duration-factory-scale.cpp +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -1,32 +1,6 @@ -// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t +// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t -- -- -I %S/Inputs -// Mimic the implementation of absl::Duration -namespace absl { - -class Duration {}; - -Duration Nanoseconds(long long); -Duration Microseconds(long long); -Duration Milliseconds(long long); -Duration Seconds(long long); -Duration Minutes(long long); -Duration Hours(long long); - -#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ - Duration NAME(float n); \ - Duration NAME(double n);\ - template\ - Duration NAME(T n); - -GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); -GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds);
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright added a comment. Ping. I assume I've got the right reviewers here, but I've also been sending a bunch of stuff your way lately, so if I'm overwhelming review capacity, please let me know. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55245: [clang-tidy] Add the abseil-duration-subtraction check
hwright updated this revision to Diff 176757. hwright marked an inline comment as done. hwright added a comment. Fix double space. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55245/new/ https://reviews.llvm.org/D55245 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h clang-tidy/abseil/DurationSubtractionCheck.cpp clang-tidy/abseil/DurationSubtractionCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-subtraction.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-subtraction.cpp Index: test/clang-tidy/abseil-duration-subtraction.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-subtraction.cpp @@ -0,0 +1,112 @@ +// RUN: %check_clang_tidy %s abseil-duration-subtraction %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d, d1; + + x = absl::ToDoubleSeconds(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(1)) + x = absl::ToDoubleSeconds(d) - absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - d1); + x = absl::ToDoubleSeconds(d) - 6.5 - 8.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleSeconds(d - absl::Seconds(6.5)) - 8.0; + x = absl::ToDoubleHours(d) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleHours(d - absl::Hours(1)) + x = absl::ToDoubleMinutes(d) - 1; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMinutes(d - absl::Minutes(1)) + x = absl::ToDoubleMilliseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMilliseconds(d - absl::Milliseconds(9)) + x = absl::ToDoubleMicroseconds(d) - 9; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleMicroseconds(d - absl::Microseconds(9)) + x = absl::ToDoubleNanoseconds(d) - 42; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform subtraction in the duration domain [abseil-duration-subtraction] + // CHECK-FIXES: absl::ToDoubleNanoseconds(d - absl::Nanoseconds(42)) + + // We can rewrite the argument of the duration conversion +#define THIRTY absl::Seconds(30) + x = absl::ToDoubleSeconds(THIRTY) - 1.0; + // CHECK-MESSAGES: [[@LINE-1]]:7:
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright added a comment. Oh, and thanks for taking the time to review this. :) CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright added a comment. @JonasToth reminder that you (or somebody else) will need to commit this for me. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright updated this revision to Diff 176156. hwright marked 2 inline comments as done. hwright added a comment. Add additional test CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationComparisonCheck.h clang-tidy/abseil/DurationFactoryFloatCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -0,0 +1,195 @@ +// RUN: %check_clang_tidy %s abseil-duration-comparison %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) > d1; + b = x >= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) >= d1; + b = x == absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == d1; + b = x <= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) <= d1; + b = x < absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) < d1; + b = x == absl::ToDoubleSeconds(t1 - t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == t1 - t2; + b = absl::ToDoubleSeconds(d1) > absl::ToDoubleSeconds(d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 > d2; + + // Check against the LHS + b = absl::ToDoubleSeconds(d1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 < absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 <= absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) == x; + //
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright updated this revision to Diff 176103. hwright added a comment. Slightly simplify the fixit text CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationComparisonCheck.h clang-tidy/abseil/DurationFactoryFloatCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -0,0 +1,189 @@ +// RUN: %check_clang_tidy %s abseil-duration-comparison %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) > d1; + b = x >= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) >= d1; + b = x == absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == d1; + b = x <= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) <= d1; + b = x < absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) < d1; + b = x == absl::ToDoubleSeconds(t1 - t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == t1 - t2; + b = absl::ToDoubleSeconds(d1) > absl::ToDoubleSeconds(d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 > d2; + + // Check against the LHS + b = absl::ToDoubleSeconds(d1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 < absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 <= absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) == x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning:
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright marked an inline comment as done. hwright added a comment. Ping. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright marked 4 inline comments as done. hwright added inline comments. Comment at: clang-tidy/abseil/DurationFactoryFloatCheck.cpp:61 + + if (SimpleArg) { diag(MatchedCall->getBeginLoc(), JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > hwright wrote: > > > > JonasToth wrote: > > > > > The diagnostic is not printed if for some reason the fixit was not > > > > > creatable. I think that the warning could still be emitted (`auto > > > > > Diag = diag(...); if (Fix) Diag << Fixit::-...`) > > > > I'm not sure under which conditions you'd expect this to be an issue. > > > > Could you give me an example? > > > > > > > > My expectation is that if we don't get a value back in `SimpleArg`, we > > > > don't have anything to change, so there wouldn't be a warning to emit. > > > I don't expect this to fail, failure there would mean a bug i guess. > > > Having bugs is somewhat expected :) > > > And that would be our way to find the bug, because some user reports that > > > there is no transformation done, that is my motivation behind that. > > > > > > The warning itself should be correct, otherwise the matcher does not > > > work, right? This would just be precaution. > > I guess what I'm saying is that I'm not sure what kind of warning we'd give > > if we weren't able to offer a fix. The optionality here means that we > > found a result which was already as simple as we can make it, so there's no > > reason to bother the user. > Lets say the result comes out of arithmetic and then there is a comparison > (would be good test btw :)), the warning is still valueable, even if the > transformation fails for some reason. The transformation could fail as well, > because macros interfere or so. Past experience tells me, there are enough > language constructs to break everything in weird combinations :) I can buy that, but I'm still having trouble seeing the specifics. Do you have a concrete example? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright marked 4 inline comments as done. hwright added inline comments. Comment at: clang-tidy/abseil/DurationDivisionCheck.h:23 // http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-division.html class DurationDivisionCheck : public ClangTidyCheck { JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > I think that blank line could be removed, and it seems the comment is not > > > ///, could you take a look at it too? > > > Touching this file is probably better to do in another patch anyway. > > Agreed. I think this snuck into the patch; I'll remove it. > > > > (It would be good to just `clang-format` everything in this directory in a > > separate patch.) > > > > The comment issue with `///` seems to be a common problem; is > > `clang-tidy/add_new_check.py` not generating correct code? > add_new_check does ///, maybe IDE settings or so removed these? Maybe someone > created everything manually, dunno. > > Doing the clang-format is ok, doesn't need review either (but plz run the > test before committing to master). I don't think I yet have the commit bit...so somebody else wouldn't need to directly commit. :) Comment at: clang-tidy/abseil/DurationFactoryFloatCheck.cpp:61 + + if (SimpleArg) { diag(MatchedCall->getBeginLoc(), JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > The diagnostic is not printed if for some reason the fixit was not > > > creatable. I think that the warning could still be emitted (`auto Diag = > > > diag(...); if (Fix) Diag << Fixit::-...`) > > I'm not sure under which conditions you'd expect this to be an issue. > > Could you give me an example? > > > > My expectation is that if we don't get a value back in `SimpleArg`, we > > don't have anything to change, so there wouldn't be a warning to emit. > I don't expect this to fail, failure there would mean a bug i guess. Having > bugs is somewhat expected :) > And that would be our way to find the bug, because some user reports that > there is no transformation done, that is my motivation behind that. > > The warning itself should be correct, otherwise the matcher does not work, > right? This would just be precaution. I guess what I'm saying is that I'm not sure what kind of warning we'd give if we weren't able to offer a fix. The optionality here means that we found a result which was already as simple as we can make it, so there's no reason to bother the user. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:69 + // We know our map contains all the Scale values, so we can skip the + // nonexistence check. + auto InverseIter = InverseMap.find(Scale); JonasToth wrote: > non-existence? Not sure about english, but i thought english does it that way https://www.merriam-webster.com/dictionary/nonexistence tells me the hyphen isn't required. Comment at: clang-tidy/abseil/DurationDivisionCheck.h:23 // http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-division.html class DurationDivisionCheck : public ClangTidyCheck { JonasToth wrote: > I think that blank line could be removed, and it seems the comment is not > ///, could you take a look at it too? > Touching this file is probably better to do in another patch anyway. Agreed. I think this snuck into the patch; I'll remove it. (It would be good to just `clang-format` everything in this directory in a separate patch.) The comment issue with `///` seems to be a common problem; is `clang-tidy/add_new_check.py` not generating correct code? Comment at: clang-tidy/abseil/DurationFactoryFloatCheck.cpp:61 + + if (SimpleArg) { diag(MatchedCall->getBeginLoc(), JonasToth wrote: > The diagnostic is not printed if for some reason the fixit was not creatable. > I think that the warning could still be emitted (`auto Diag = diag(...); if > (Fix) Diag << Fixit::-...`) I'm not sure under which conditions you'd expect this to be an issue. Could you give me an example? My expectation is that if we don't get a value back in `SimpleArg`, we don't have anything to change, so there wouldn't be a warning to emit. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright updated this revision to Diff 175735. hwright marked 13 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationComparisonCheck.h clang-tidy/abseil/DurationFactoryFloatCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -0,0 +1,189 @@ +// RUN: %check_clang_tidy %s abseil-duration-comparison %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) > d1; + b = x >= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) >= d1; + b = x == absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == d1; + b = x <= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) <= d1; + b = x < absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) < d1; + b = x == absl::ToDoubleSeconds(t1 - t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == t1 - t2; + b = absl::ToDoubleSeconds(d1) > absl::ToDoubleSeconds(d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 > d2; + + // Check against the LHS + b = absl::ToDoubleSeconds(d1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 < absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 <= absl::Seconds(x); + b =
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright marked 2 inline comments as done. hwright added a comment. Anything else for me here? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright marked 12 inline comments as done. hwright added inline comments. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:25 +static llvm::Optional getScaleForInverse(llvm::StringRef Name) { + static const std::unordered_map ScaleMap( + {{"ToDoubleHours", DurationScale::Hours}, aaron.ballman wrote: > sammccall wrote: > > aaron.ballman wrote: > > > sammccall wrote: > > > > aaron.ballman wrote: > > > > > sammccall wrote: > > > > > > hwright wrote: > > > > > > > JonasToth wrote: > > > > > > > > hwright wrote: > > > > > > > > > JonasToth wrote: > > > > > > > > > > I think this could be made a `DenseMap` with just the right > > > > > > > > > > amount of dense entries. 12 elements seems not too much to > > > > > > > > > > me. > > > > > > > > > > Does the key-type need to be `std::string`, or could it be > > > > > > > > > > `StringRef`(or `StringLiteral` making everything > > > > > > > > > > `constexpr` if possible)? > > > > > > > > > > Is there some strange stuff with dangling pointers or other > > > > > > > > > > issues going on? > > > > > > > > > Conceptually, this could easily be `constexpr`, but my > > > > > > > > > compiler doesn't seem to want to build something which is > > > > > > > > > called `static constexpr llvm::DenseMap > > > > > > > > DurationScale>`. It's chief complaint is that such a type > > > > > > > > > has a non-trivial destructor. Am I using this correctly? > > > > > > > > I honestly never tried to make a `constexpr DenseMap<>` but it > > > > > > > > makes sense it is not possible, as `DenseMap` is involved with > > > > > > > > dynamic memory after all, which is not possible with > > > > > > > > `constexpr` (yet). So you were my test-bunny ;) > > > > > > > > > > > > > > > > I did reread the Data-structures section in the LLVM manual, i > > > > > > > > totally forgot about `StringMap` that maps strings to values. > > > > > > > > `DenseMap` is good when mapping small values to each other, as > > > > > > > > we do here (`const char* -> int (whatever the enum deduces > > > > > > > > too)`), which would fit. > > > > > > > > `StringMap` does allocations for the strings, which we don't > > > > > > > > need. > > > > > > > > > > > > > > > > `constexpr` aside my bet is that `DenseMap` fits this case the > > > > > > > > better, because we can lay every thing out and never touch it > > > > > > > > again. Maybe someone else has better arguments for the decision > > > > > > > > :) > > > > > > > > > > > > > > > > Soo: could you please try `static const > > > > > > > > llvm::DenseMap`? :) > > > > > > > > (should work in theory: https://godbolt.org/z/Qo7Nv4) > > > > > > > `static const llvm::DenseMap` > > > > > > > works here. :) > > > > > > Sorry for the drive-by... > > > > > > This has a non-trivial destructor, so violates > > > > > > https://llvm.org/docs/CodingStandards.html#do-not-use-static-constructors > > > > > > at least in spirit. > > > > > > > > > > > > Best to leak it (`auto = *new const > > > > > > llvm::DenseMap<...>(...)`) to avoid the destructor issues. The > > > > > > constructor issues are already handled by making it function-local. > > > > > I do not think this violates the coding standard -- that's talking > > > > > mostly about global objects, not local objects, and is concerned > > > > > about startup performance and initialization orders. I don't see any > > > > > destructor ordering issues with this, so I do not think any of that > > > > > applies here and leaking would be less than ideal. > > > > There are three main issues with global objects that the coding > > > > standard mentions: > > > > - performance when unused. Not relevant to function-local statics, > > > > only constructed when used > > > > - static initialization order fiasco (constructors). Not relevant to > > > > function-local statics, constructed in well-defined order > > > > - static initialization order fiasco (destructors). Just as relevant > > > > to function-local statics as to any other object! > > > > > > > > That's why I say it violates the rule in spirit: the destructor is > > > > global. https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2 > > > > > > > > > I don't see any destructor ordering issues with this > > > > The reason these constructs are disallowed in coding guidelines is that > > > > humans can't see the problems, and they manifest in non-local ways :-( > > > > > > > > > leaking would be less than ideal > > > > Why? The current code will (usually) destroy the object when the > > > > program exits. This is a waste of CPU, the OS will free the memory. > > > > The reason these constructs are disallowed in coding guidelines is that > > > > humans can't see the problems, and they manifest in non-local ways :-( > > > > > > Can you explain why you think this would have any non-local impact on > > > destruction? The DenseMap is local to the function and a pointer to it > > > never escapes
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:25 +static llvm::Optional getScaleForInverse(llvm::StringRef Name) { + static const std::unordered_map ScaleMap( + {{"ToDoubleHours", DurationScale::Hours}, JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > I think this could be made a `DenseMap` with just the right amount of > > > dense entries. 12 elements seems not too much to me. > > > Does the key-type need to be `std::string`, or could it be `StringRef`(or > > > `StringLiteral` making everything `constexpr` if possible)? > > > Is there some strange stuff with dangling pointers or other issues going > > > on? > > Conceptually, this could easily be `constexpr`, but my compiler doesn't > > seem to want to build something which is called `static constexpr > > llvm::DenseMap`. It's chief complaint is > > that such a type has a non-trivial destructor. Am I using this correctly? > I honestly never tried to make a `constexpr DenseMap<>` but it makes sense it > is not possible, as `DenseMap` is involved with dynamic memory after all, > which is not possible with `constexpr` (yet). So you were my test-bunny ;) > > I did reread the Data-structures section in the LLVM manual, i totally forgot > about `StringMap` that maps strings to values. > `DenseMap` is good when mapping small values to each other, as we do here > (`const char* -> int (whatever the enum deduces too)`), which would fit. > `StringMap` does allocations for the strings, which we don't need. > > `constexpr` aside my bet is that `DenseMap` fits this case the better, > because we can lay every thing out and never touch it again. Maybe someone > else has better arguments for the decision :) > > Soo: could you please try `static const llvm::DenseMap DurationScale>`? :) > (should work in theory: https://godbolt.org/z/Qo7Nv4) `static const llvm::DenseMap` works here. :) Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:50 + static const std::unordered_map> + InverseMap( hwright wrote: > JonasToth wrote: > > This variable is a little hard to read. Could you make a little > > wrapper-struct instead of the `tuple` to make clear which element > > represents what? > > Otherwise, why not `std::pair`? > > > > - same `DenseMap` argument > > - same `StringRef`/`StringLiteral` instead `string` consideration > `std::pair` works here. > > I'll defer the `DenseMap` and `StringRef`/`StringLiteral` changes until we > determine if they are actually possible. ...but using `DenseMap` here doesn't work. From the mountains of compiler output I get when I try, it appears that `DenseMap` adds some constraints on the key type, and an `enum class` doesn't meet those constraints. fwiw, the errors are mostly of this form: ``` /llvm/llvm/include/llvm/ADT/DenseMap.h:1277:45: error: ‘getEmptyKey’ is not a member of ‘llvm::DenseMapInfo’ const KeyT Empty = KeyInfoT::getEmptyKey(); ~^~ /llvm/llvm/include/llvm/ADT/DenseMap.h:1278:53: error: ‘getTombstoneKey’ is not a member of ‘llvm::DenseMapInfo’ const KeyT Tombstone = KeyInfoT::getTombstoneKey(); ~^~ /llvm/llvm/include/llvm/ADT/DenseMap.h:1280:44: error: ‘isEqual’ is not a member of ‘llvm::DenseMapInfo’ while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) || ~^~~ /llvm/llvm/include/llvm/ADT/DenseMap.h:1281:44: error: ‘isEqual’ is not a member of ‘llvm::DenseMapInfo’ KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone))) ``` Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:125 + hasAnyName( + "::absl::ToDoubleHours", "::absl::ToDoubleMinutes", + "::absl::ToDoubleSeconds", "::absl::ToDoubleMilliseconds", JonasToth wrote: > hwright wrote: > > JonasToth wrote: > > > the list here is somewhat duplicated with the static members in the > > > functions at the top. it would be best to merge them. > > > Not sure on how much `constexpr` is supported by the llvm-datastructures, > > > but a constexpr `DenseMap.keys()` would be nice. Did you try something > > > along this line? > > I haven't tried that exact formulation, but given the above issue with > > `DenseMap`, I'm not sure it will work. Happy to try once we get it ironed > > out. > > > > Another thing I've thought about is factoring the `functionDecl` matcher > > into a separate function, because I expect it to be reused. I haven't been > > able to deduce what type that function would return. > the type is probably `clang::ast_matchers::internal::Matcher`. > Not sure what the `bind` does with the type though. > > If that is not the case you can make a nice error with `int Bad = >
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright updated this revision to Diff 175476. hwright marked 10 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationComparisonCheck.h clang-tidy/abseil/DurationDivisionCheck.h clang-tidy/abseil/DurationFactoryFloatCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -0,0 +1,189 @@ +// RUN: %check_clang_tidy %s abseil-duration-comparison %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) > d1; + b = x >= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) >= d1; + b = x == absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == d1; + b = x <= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) <= d1; + b = x < absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) < d1; + b = x == absl::ToDoubleSeconds(t1 - t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == t1 - t2; + b = absl::ToDoubleSeconds(d1) > absl::ToDoubleSeconds(d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 > d2; + + // Check against the LHS + b = absl::ToDoubleSeconds(d1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 < absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright added a comment. Sorry it's taken so long to get all the feedback addressed! Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:25 +static llvm::Optional getScaleForInverse(llvm::StringRef Name) { + static const std::unordered_map ScaleMap( + {{"ToDoubleHours", DurationScale::Hours}, JonasToth wrote: > I think this could be made a `DenseMap` with just the right amount of dense > entries. 12 elements seems not too much to me. > Does the key-type need to be `std::string`, or could it be `StringRef`(or > `StringLiteral` making everything `constexpr` if possible)? > Is there some strange stuff with dangling pointers or other issues going on? Conceptually, this could easily be `constexpr`, but my compiler doesn't seem to want to build something which is called `static constexpr llvm::DenseMap`. It's chief complaint is that such a type has a non-trivial destructor. Am I using this correctly? Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:50 + static const std::unordered_map> + InverseMap( JonasToth wrote: > This variable is a little hard to read. Could you make a little > wrapper-struct instead of the `tuple` to make clear which element represents > what? > Otherwise, why not `std::pair`? > > - same `DenseMap` argument > - same `StringRef`/`StringLiteral` instead `string` consideration `std::pair` works here. I'll defer the `DenseMap` and `StringRef`/`StringLiteral` changes until we determine if they are actually possible. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:68 + + // We know our map contains all the Scale values, so we can skip the + // nonexistence check. JonasToth wrote: > The basis for this "we know" might change in the future if `abs::Duration` > does things differently. Is adding stuff allowed in the `absl::` space? (i am > not fluent with the guarantees that it gives). You could maybe `assert` that > the find is always correct, depending on `absl` guarantees. `absl::` could add things. In this case, I'm very confident they won't, but I've still added the assert. Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:108 + + // TODO(hwright): Check for another condition: + // 1. duration-factory-scale JonasToth wrote: > in LLVM the TODO does not contain a name for the author. I just removed the TODO (this isn't a required part of the check). Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:125 + hasAnyName( + "::absl::ToDoubleHours", "::absl::ToDoubleMinutes", + "::absl::ToDoubleSeconds", "::absl::ToDoubleMilliseconds", JonasToth wrote: > the list here is somewhat duplicated with the static members in the functions > at the top. it would be best to merge them. > Not sure on how much `constexpr` is supported by the llvm-datastructures, but > a constexpr `DenseMap.keys()` would be nice. Did you try something along this > line? I haven't tried that exact formulation, but given the above issue with `DenseMap`, I'm not sure it will work. Happy to try once we get it ironed out. Another thing I've thought about is factoring the `functionDecl` matcher into a separate function, because I expect it to be reused. I haven't been able to deduce what type that function would return. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
hwright updated this revision to Diff 175379. hwright marked 23 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D54737/new/ https://reviews.llvm.org/D54737 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationComparisonCheck.cpp clang-tidy/abseil/DurationComparisonCheck.h clang-tidy/abseil/DurationDivisionCheck.h clang-tidy/abseil/DurationFactoryFloatCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationRewriter.cpp clang-tidy/abseil/DurationRewriter.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-comparison.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-comparison.cpp Index: test/clang-tidy/abseil-duration-comparison.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-comparison.cpp @@ -0,0 +1,189 @@ +// RUN: %check_clang_tidy %s abseil-duration-comparison %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; +class Time{}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +using int64_t = long long int; + +double ToDoubleHours(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleNanoseconds(Duration d); +int64_t ToInt64Hours(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Nanoseconds(Duration d); + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs); +constexpr bool operator>=(Duration lhs, Duration rhs); +constexpr bool operator<=(Duration lhs, Duration rhs); +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs); + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs); +inline Time operator+(Duration lhs, Time rhs); +inline Time operator-(Time lhs, Duration rhs); +inline Duration operator-(Time lhs, Time rhs); + +} // namespace absl + +void f() { + double x; + absl::Duration d1, d2; + bool b; + absl::Time t1, t2; + + // Check against the RHS + b = x > absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) > d1; + b = x >= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) >= d1; + b = x == absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == d1; + b = x <= absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) <= d1; + b = x < absl::ToDoubleSeconds(d1); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) < d1; + b = x == absl::ToDoubleSeconds(t1 - t2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: absl::Seconds(x) == t1 - t2; + b = absl::ToDoubleSeconds(d1) > absl::ToDoubleSeconds(d2); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 > d2; + + // Check against the LHS + b = absl::ToDoubleSeconds(d1) < x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1 < absl::Seconds(x); + b = absl::ToDoubleSeconds(d1) <= x; + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: perform duration comparison in the duration domain [abseil-duration-comparison] + // CHECK-FIXES: d1
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright added a comment. @aaron.ballman I don't actually have the commit bit, can you commit this, or are we waiting for further review? https://reviews.llvm.org/D54246 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright added a comment. I think this is ready to go, please advise on next steps. https://reviews.llvm.org/D54246 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright marked 5 inline comments as done. hwright added inline comments. Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:73 + case DurationScale::Hours: +if (Multiplier <= 1.0 / 60.0) + return std::make_tuple(DurationScale::Minutes, Multiplier * 60.0); aaron.ballman wrote: > This doesn't seem quite right. `1.0/6000.0` is less than `1.0/60.0` but isn't > a `Minutes` scaling. After spending two days chasing this down, it finally occurred to me: we don't actually handle this case. Our (somewhat conservative) matchers only look for literal values, not division expressions like `1.0/60.0`. And for this iteration of the tool, I think I'm fine with that, since I expect those kinds of things to be exceedingly rare, and probably tricky to handle, anyway. https://reviews.llvm.org/D54246 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:57-58 +// One and only one of `IntLit` and `FloatLit` should be provided. +static double GetValue(const IntegerLiteral *IntLit, + const FloatingLiteral *FloatLit) { + if (IntLit) { aaron.ballman wrote: > hwright wrote: > > aaron.ballman wrote: > > > I really don't like this interface where you pass two arguments, only one > > > of which is ever valid. That is pretty confusing. Given that the result > > > of this function is only ever passed to `GetNewMultScale()`, and that > > > function only does integral checks, I'd prefer logic more like: > > > > > > * If the literal is integral, get its value and call `GetNewMultScale()`. > > > * If the literal is float, convert it to an integral and call > > > `GetNewMultScale()` only if the conversion is exact (this can be done via > > > `APFloat::convertToInteger()`). > > > * `GetNewMultScale()` can now accept an integer value and removes the > > > questions about inexact equality tests from the function. > > > > > > With that logic, I don't see a need for `GetValue()` at all, but if a > > > helper function is useful, I'd probably guess this is a better signature: > > > `int64_t getIntegralValue(const Expr *Literal, bool );` > > > Given that the result of this function is only ever passed to > > > `GetNewMultScale()`, and that function only does integral checks, I'd > > > prefer logic more like: > > > > That's actually not true: `GetNewMultScale()` does checks against values > > like `1e-3` which aren't integers. Does this change your suggestion? > Hmm, yeah, I suppose it has to! :-D I've reworked the bulk of this logic. It still uses doubles, but that doesn't trouble our test cases. Please let me know if there's more to do here. Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:63 + assert(FloatLit != nullptr && "Neither IntLit nor FloatLit set"); + return FloatLit->getValueAsApproximateDouble(); +} aaron.ballman wrote: > hwright wrote: > > aaron.ballman wrote: > > > I believe the approximate results here can lead to bugs where the > > > floating-point literal is subnormal -- it may return 0.0 for literals > > > that are not zero. > > Do you have an example which I could put in a test? > `0x0.01p-126f` should get you a new, exciting way to spell `0`. I've added this as a test, and it resolves as normal. Was your comment intended to indicate that it //should//, or that doing so would be a bug? Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:81-84 +if (Multiplier == 60.0) + return DurationScale::Minutes; +if (Multiplier == 1e-3) + return DurationScale::Milliseconds; aaron.ballman wrote: > hwright wrote: > > aaron.ballman wrote: > > > What about scaling with a multiplier of 3600 to go from seconds to hours, > > > and other plausible conversions? > > That's a good point, and part of a broader design discussion: should we > > support all multipliers? (e.g., what about multiplying microseconds by > > `1.0/864.0`?) > > > > If we do think it's worth handling all of these cases, we probably want a > > different construct than the equivalent of a lookup table to do this > > computation. > > That's a good point, and part of a broader design discussion: should we > > support all multipliers? > > That's kind of what I'm leaning towards. It's certainly more explainable to > users that all the various scaling operations just work, rather than some > particular set. > > However, maybe you know more about the user base than I do and there's a > sound reason to not handle all cases? > > > If we do think it's worth handling all of these cases, we probably want a > > different construct than the equivalent of a lookup table to do this > > computation. > > There's a part of me that wonders if we can use `std::ratio` to describe the > scaling operations, but I freely admit I've not thought about implementation > strategies all that hard. `std::ratio` didn't look like it made much sense here (though I don't have much first-hand experience using it), but we do now handle multiple scaling steps. https://reviews.llvm.org/D54246 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright updated this revision to Diff 174039. hwright marked 11 inline comments as done. hwright added a comment. Combined multiplication and division logic, and also now handles scaling of multiple steps (e.g., Seconds * 3600). https://reviews.llvm.org/D54246 Files: clang-tidy/abseil/AbseilTidyModule.cpp clang-tidy/abseil/CMakeLists.txt clang-tidy/abseil/DurationFactoryScaleCheck.cpp clang-tidy/abseil/DurationFactoryScaleCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/abseil-duration-factory-scale.rst docs/clang-tidy/checks/list.rst test/clang-tidy/abseil-duration-factory-scale.cpp Index: test/clang-tidy/abseil-duration-factory-scale.cpp === --- /dev/null +++ test/clang-tidy/abseil-duration-factory-scale.cpp @@ -0,0 +1,130 @@ +// RUN: %check_clang_tidy %s abseil-duration-factory-scale %t + +// Mimic the implementation of absl::Duration +namespace absl { + +class Duration {}; + +Duration Nanoseconds(long long); +Duration Microseconds(long long); +Duration Milliseconds(long long); +Duration Seconds(long long); +Duration Minutes(long long); +Duration Hours(long long); + +#define GENERATE_DURATION_FACTORY_OVERLOADS(NAME) \ + Duration NAME(float n); \ + Duration NAME(double n);\ + template\ + Duration NAME(T n); + +GENERATE_DURATION_FACTORY_OVERLOADS(Nanoseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Microseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Milliseconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Seconds); +GENERATE_DURATION_FACTORY_OVERLOADS(Minutes); +GENERATE_DURATION_FACTORY_OVERLOADS(Hours); +#undef GENERATE_DURATION_FACTORY_OVERLOADS + +} // namespace absl + +void ScaleTest() { + absl::Duration d; + + // Zeroes + d = absl::Hours(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Minutes(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Milliseconds(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Microseconds(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Nanoseconds(0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(0.0); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + d = absl::Seconds(0x0.01p-126f); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use ZeroDuration() for zero-length time intervals [abseil-duration-factory-scale] + // CHECK-FIXES: absl::ZeroDuration(); + + // Fold seconds into minutes + d = absl::Seconds(30 * 60); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Minutes(30); + d = absl::Seconds(60 * 30); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Minutes(30); + + // Try a few more exotic multiplications + d = absl::Seconds(60 * 30 * 60); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Minutes(60 * 30); + d = absl::Seconds(1e-3 * 30); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Milliseconds(30); + d = absl::Milliseconds(30 * 1000); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Seconds(30); + d = absl::Milliseconds(30 * 0.001); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Microseconds(30); + + // Multiple steps + d = absl::Seconds(5 * 3600); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed [abseil-duration-factory-scale] + // CHECK-FIXES: absl::Hours(5); + d = absl::Microseconds(5 * 1e6); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: internal duration scaling can be removed
[PATCH] D54246: [clang-tidy] Add the abseil-duration-factory-scale check
hwright added inline comments. Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:57-58 +// One and only one of `IntLit` and `FloatLit` should be provided. +static double GetValue(const IntegerLiteral *IntLit, + const FloatingLiteral *FloatLit) { + if (IntLit) { aaron.ballman wrote: > I really don't like this interface where you pass two arguments, only one of > which is ever valid. That is pretty confusing. Given that the result of this > function is only ever passed to `GetNewMultScale()`, and that function only > does integral checks, I'd prefer logic more like: > > * If the literal is integral, get its value and call `GetNewMultScale()`. > * If the literal is float, convert it to an integral and call > `GetNewMultScale()` only if the conversion is exact (this can be done via > `APFloat::convertToInteger()`). > * `GetNewMultScale()` can now accept an integer value and removes the > questions about inexact equality tests from the function. > > With that logic, I don't see a need for `GetValue()` at all, but if a helper > function is useful, I'd probably guess this is a better signature: `int64_t > getIntegralValue(const Expr *Literal, bool );` > Given that the result of this function is only ever passed to > `GetNewMultScale()`, and that function only does integral checks, I'd prefer > logic more like: That's actually not true: `GetNewMultScale()` does checks against values like `1e-3` which aren't integers. Does this change your suggestion? Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:63 + assert(FloatLit != nullptr && "Neither IntLit nor FloatLit set"); + return FloatLit->getValueAsApproximateDouble(); +} aaron.ballman wrote: > I believe the approximate results here can lead to bugs where the > floating-point literal is subnormal -- it may return 0.0 for literals that > are not zero. Do you have an example which I could put in a test? Comment at: clang-tidy/abseil/DurationFactoryScaleCheck.cpp:81-84 +if (Multiplier == 60.0) + return DurationScale::Minutes; +if (Multiplier == 1e-3) + return DurationScale::Milliseconds; aaron.ballman wrote: > What about scaling with a multiplier of 3600 to go from seconds to hours, and > other plausible conversions? That's a good point, and part of a broader design discussion: should we support all multipliers? (e.g., what about multiplying microseconds by `1.0/864.0`?) If we do think it's worth handling all of these cases, we probably want a different construct than the equivalent of a lookup table to do this computation. https://reviews.llvm.org/D54246 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits