[PATCH] D54737: [clang-tidy] Add the abseil-duration-comparison check
Jonas Toth via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 20 02:10:32 PST 2018
JonasToth added a comment.
Could you please upload the diff with full context? Especially the parts with refactoring are harder to judge if the code around is not visible. Thank you :)
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:25
+static llvm::Optional<DurationScale> getScaleForInverse(llvm::StringRef Name) {
+ static const std::unordered_map<std::string, DurationScale> ScaleMap(
+ {{"ToDoubleHours", DurationScale::Hours},
----------------
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?
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:50
+ static const std::unordered_map<DurationScale,
+ std::tuple<std::string, std::string>>
+ InverseMap(
----------------
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
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:68
+
+ // We know our map contains all the Scale values, so we can skip the
+ // nonexistence check.
----------------
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.
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:78
+ DurationScale Scale, const Expr &Node) {
+ auto InverseFunctions = getInverseForScale(Scale);
+ if (auto MaybeCallArg = selectFirst<const Expr>(
----------------
Please no `auto` here
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:79
+ auto InverseFunctions = getInverseForScale(Scale);
+ if (auto MaybeCallArg = selectFirst<const Expr>(
+ "e", match(callExpr(callee(functionDecl(hasAnyName(
----------------
Please use `const auto*` to make it clear that this is a pointer
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:99
+ // First check to see if we can undo a complimentary function call.
+ if (auto MaybeRewrite =
+ maybeRewriteInverseDurationCall(Result, Scale, RootNode)) {
----------------
please no `auto`, you can ellide the braces
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:104
+
+ if (IsLiteralZero(Result, RootNode)) {
+ return "absl::ZeroDuration()";
----------------
ellide braces
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:108
+
+ // TODO(hwright): Check for another condition:
+ // 1. duration-factory-scale
----------------
in LLVM the TODO does not contain a name for the author.
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:125
+ hasAnyName(
+ "::absl::ToDoubleHours", "::absl::ToDoubleMinutes",
+ "::absl::ToDoubleSeconds", "::absl::ToDoubleMilliseconds",
----------------
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?
================
Comment at: clang-tidy/abseil/DurationComparisonCheck.cpp:151
+ // if nothing needs to be done.
+ auto lhs_replacement =
+ rewriteExprFromNumberToDuration(Result, *Scale, Binop->getLHS());
----------------
Please follow the naming convention and don't use `auto` here.
================
Comment at: clang-tidy/abseil/DurationFactoryFloatCheck.cpp:61
+ llvm::Optional<std::string> SimpleArg = stripFloatCast(Result, *Arg);
+ if (!SimpleArg) {
+ SimpleArg = stripFloatLiteralFraction(Result, *Arg);
----------------
braces can be ellided here
================
Comment at: clang-tidy/abseil/DurationRewriter.cpp:51
+bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node) {
+ return selectFirst<const clang::Expr>(
+ "val", match(expr(ignoringImpCasts(anyOf(integerLiteral(equals(0)),
----------------
This is a implicit pointer-to-bool-conversion, isn't it? I think for readability purposes this should be made clear with a binary comparison.
================
Comment at: clang-tidy/abseil/DurationRewriter.cpp:61
+ const Expr &Node) {
+ if (auto MaybeCastArg = selectFirst<const Expr>(
+ "cast_arg",
----------------
`const auto *`
================
Comment at: clang-tidy/abseil/DurationRewriter.cpp:95
+ // Check for an explicit cast to `float` or `double`.
+ if (auto MaybeArg = stripFloatCast(Result, Node)) {
+ return *MaybeArg;
----------------
please no `auto`, braces
================
Comment at: clang-tidy/abseil/DurationRewriter.cpp:100
+ // Check for floats without fractional components.
+ if (auto MaybeArg = stripFloatLiteralFraction(Result, Node)) {
+ return *MaybeArg;
----------------
same
================
Comment at: docs/clang-tidy/checks/abseil-duration-comparison.rst:10
+N.B.: In cases where a ``Duration`` was being converted to an integer and then
+compared against a floating-pointer value, truncation during the ``Duration``
+conversion might yield a different result. In practice this is very rare, and
----------------
'floating-pointer' -> 'floating-point'?
================
Comment at: test/clang-tidy/abseil-duration-comparison.cpp:68
+ // 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]
----------------
The test-cases miss macros and templates, please add reasonable cases for each of these categories.
================
Comment at: test/clang-tidy/abseil-duration-comparison.cpp:89
+ // CHECK-FIXES: d1 > d2;
+
+ // Check against the LHS
----------------
What would happen for a type, that can implicitly convert to a duration or double/int.
```
struct MetaBenchmarkResults {
int64_t RunID;
absl::Duration D;
operator absl::Duration() { return D; }
};
auto R = MetaBenchmarkResults { /* Foo */ };
bool WithinReason = Threshold < R;
```
What is the correct behaviour there? I think this should be diagnosed too.
================
Comment at: test/clang-tidy/abseil-duration-comparison.cpp:161
+ // These should not match
+ b = 6 < 4;
+}
----------------
could you please add a cases similiar to this:
```
if (some_condition && very_very_very_long_variable_name
< SomeDuration) {
// ...
}
```
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D54737
More information about the cfe-commits
mailing list