[clang-tidy] Add the abseil-time-subtraction check
Differential Revision: https://reviews.llvm.org/D58137 llvm-svn: 355024
This commit is contained in:
parent
ac552f77f4
commit
c526e02668
|
@ -23,6 +23,7 @@
|
|||
#include "RedundantStrcatCallsCheck.h"
|
||||
#include "StringFindStartswithCheck.h"
|
||||
#include "StrCatAppendCheck.h"
|
||||
#include "TimeSubtractionCheck.h"
|
||||
#include "UpgradeDurationConversionsCheck.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -59,6 +60,8 @@ public:
|
|||
"abseil-str-cat-append");
|
||||
CheckFactories.registerCheck<StringFindStartswithCheck>(
|
||||
"abseil-string-find-startswith");
|
||||
CheckFactories.registerCheck<TimeSubtractionCheck>(
|
||||
"abseil-time-subtraction");
|
||||
CheckFactories.registerCheck<UpgradeDurationConversionsCheck>(
|
||||
"abseil-upgrade-duration-conversions");
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ add_clang_library(clangTidyAbseilModule
|
|||
RedundantStrcatCallsCheck.cpp
|
||||
StrCatAppendCheck.cpp
|
||||
StringFindStartswithCheck.cpp
|
||||
TimeSubtractionCheck.cpp
|
||||
UpgradeDurationConversionsCheck.cpp
|
||||
|
||||
LINK_LIBS
|
||||
|
|
|
@ -84,6 +84,22 @@ rewriteInverseDurationCall(const MatchFinder::MatchResult &Result,
|
|||
return llvm::None;
|
||||
}
|
||||
|
||||
/// If `Node` is a call to the inverse of `Scale`, return that inverse's
|
||||
/// argument, otherwise None.
|
||||
static llvm::Optional<std::string>
|
||||
rewriteInverseTimeCall(const MatchFinder::MatchResult &Result,
|
||||
DurationScale Scale, const Expr &Node) {
|
||||
llvm::StringRef InverseFunction = getTimeInverseForScale(Scale);
|
||||
if (const auto *MaybeCallArg = selectFirst<const Expr>(
|
||||
"e", match(callExpr(callee(functionDecl(hasName(InverseFunction))),
|
||||
hasArgument(0, expr().bind("e"))),
|
||||
Node, *Result.Context))) {
|
||||
return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
|
||||
}
|
||||
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
/// Returns the factory function name for a given `Scale`.
|
||||
llvm::StringRef getDurationFactoryForScale(DurationScale Scale) {
|
||||
switch (Scale) {
|
||||
|
@ -103,6 +119,24 @@ llvm::StringRef getDurationFactoryForScale(DurationScale Scale) {
|
|||
llvm_unreachable("unknown scaling factor");
|
||||
}
|
||||
|
||||
llvm::StringRef getTimeFactoryForScale(DurationScale Scale) {
|
||||
switch (Scale) {
|
||||
case DurationScale::Hours:
|
||||
return "absl::FromUnixHours";
|
||||
case DurationScale::Minutes:
|
||||
return "absl::FromUnixMinutes";
|
||||
case DurationScale::Seconds:
|
||||
return "absl::FromUnixSeconds";
|
||||
case DurationScale::Milliseconds:
|
||||
return "absl::FromUnixMillis";
|
||||
case DurationScale::Microseconds:
|
||||
return "absl::FromUnixMicros";
|
||||
case DurationScale::Nanoseconds:
|
||||
return "absl::FromUnixNanos";
|
||||
}
|
||||
llvm_unreachable("unknown scaling factor");
|
||||
}
|
||||
|
||||
/// Returns the Time factory function name for a given `Scale`.
|
||||
llvm::StringRef getTimeInverseForScale(DurationScale scale) {
|
||||
switch (scale) {
|
||||
|
@ -250,6 +284,24 @@ std::string rewriteExprFromNumberToDuration(
|
|||
.str();
|
||||
}
|
||||
|
||||
std::string rewriteExprFromNumberToTime(
|
||||
const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale,
|
||||
const Expr *Node) {
|
||||
const Expr &RootNode = *Node->IgnoreParenImpCasts();
|
||||
|
||||
// First check to see if we can undo a complimentary function call.
|
||||
if (llvm::Optional<std::string> MaybeRewrite =
|
||||
rewriteInverseTimeCall(Result, Scale, RootNode))
|
||||
return *MaybeRewrite;
|
||||
|
||||
if (IsLiteralZero(Result, RootNode))
|
||||
return std::string("absl::UnixEpoch()");
|
||||
|
||||
return (llvm::Twine(getTimeFactoryForScale(Scale)) + "(" +
|
||||
tooling::fixit::getText(RootNode, *Result.Context) + ")")
|
||||
.str();
|
||||
}
|
||||
|
||||
bool isNotInMacro(const MatchFinder::MatchResult &Result, const Expr *E) {
|
||||
if (!E->getBeginLoc().isMacroID())
|
||||
return true;
|
||||
|
|
|
@ -31,6 +31,10 @@ enum class DurationScale : std::uint8_t {
|
|||
/// constructing a `Duration` for that scale.
|
||||
llvm::StringRef getDurationFactoryForScale(DurationScale Scale);
|
||||
|
||||
/// Given a 'Scale', return the appropriate factory function call for
|
||||
/// constructing a `Time` for that scale.
|
||||
llvm::StringRef getTimeFactoryForScale(DurationScale scale);
|
||||
|
||||
// Determine if `Node` represents a literal floating point or integral zero.
|
||||
bool IsLiteralZero(const ast_matchers::MatchFinder::MatchResult &Result,
|
||||
const Expr &Node);
|
||||
|
@ -81,6 +85,12 @@ std::string rewriteExprFromNumberToDuration(
|
|||
const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale,
|
||||
const Expr *Node);
|
||||
|
||||
/// Assuming `Node` has a type `int` representing a time instant of `Scale`
|
||||
/// since The Epoch, return the expression to make it a suitable `Time`.
|
||||
std::string rewriteExprFromNumberToTime(
|
||||
const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale,
|
||||
const Expr *Node);
|
||||
|
||||
/// Return `true` if `E` is a either: not a macro at all; or an argument to
|
||||
/// one. In the both cases, we often want to do the transformation.
|
||||
bool isNotInMacro(const ast_matchers::MatchFinder::MatchResult &Result,
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
//===--- TimeSubtractionCheck.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 "TimeSubtractionCheck.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 {
|
||||
|
||||
// Returns `true` if `Range` is inside a macro definition.
|
||||
static bool InsideMacroDefinition(const MatchFinder::MatchResult &Result,
|
||||
SourceRange Range) {
|
||||
return !clang::Lexer::makeFileCharRange(
|
||||
clang::CharSourceRange::getCharRange(Range),
|
||||
*Result.SourceManager, Result.Context->getLangOpts())
|
||||
.isValid();
|
||||
}
|
||||
|
||||
static bool isConstructorAssignment(const MatchFinder::MatchResult &Result,
|
||||
const Expr *Node) {
|
||||
return selectFirst<const Expr>(
|
||||
"e", match(expr(hasParent(materializeTemporaryExpr(hasParent(
|
||||
cxxConstructExpr(hasParent(exprWithCleanups(
|
||||
hasParent(varDecl()))))))))
|
||||
.bind("e"),
|
||||
*Node, *Result.Context)) != nullptr;
|
||||
}
|
||||
|
||||
static bool isArgument(const MatchFinder::MatchResult &Result,
|
||||
const Expr *Node) {
|
||||
return selectFirst<const Expr>(
|
||||
"e",
|
||||
match(expr(hasParent(
|
||||
materializeTemporaryExpr(hasParent(cxxConstructExpr(
|
||||
hasParent(callExpr()),
|
||||
unless(hasParent(cxxOperatorCallExpr())))))))
|
||||
.bind("e"),
|
||||
*Node, *Result.Context)) != nullptr;
|
||||
}
|
||||
|
||||
static bool isReturn(const MatchFinder::MatchResult &Result, const Expr *Node) {
|
||||
return selectFirst<const Expr>(
|
||||
"e", match(expr(hasParent(materializeTemporaryExpr(hasParent(
|
||||
cxxConstructExpr(hasParent(exprWithCleanups(
|
||||
hasParent(returnStmt()))))))))
|
||||
.bind("e"),
|
||||
*Node, *Result.Context)) != nullptr;
|
||||
}
|
||||
|
||||
static bool parensRequired(const MatchFinder::MatchResult &Result,
|
||||
const Expr *Node) {
|
||||
// TODO: Figure out any more contexts in which we can omit the surrounding
|
||||
// parentheses.
|
||||
return !(isConstructorAssignment(Result, Node) || isArgument(Result, Node) ||
|
||||
isReturn(Result, Node));
|
||||
}
|
||||
|
||||
void TimeSubtractionCheck::emitDiagnostic(const Expr *Node,
|
||||
llvm::StringRef Replacement) {
|
||||
diag(Node->getBeginLoc(), "perform subtraction in the time domain")
|
||||
<< FixItHint::CreateReplacement(Node->getSourceRange(), Replacement);
|
||||
}
|
||||
|
||||
void TimeSubtractionCheck::registerMatchers(MatchFinder *Finder) {
|
||||
for (auto ScaleName :
|
||||
{"Hours", "Minutes", "Seconds", "Millis", "Micros", "Nanos"}) {
|
||||
std::string TimeInverse = (llvm::Twine("ToUnix") + ScaleName).str();
|
||||
llvm::Optional<DurationScale> Scale = getScaleForTimeInverse(TimeInverse);
|
||||
assert(Scale && "Unknow scale encountered");
|
||||
|
||||
auto TimeInverseMatcher = callExpr(callee(
|
||||
functionDecl(hasName((llvm::Twine("::absl::") + TimeInverse).str()))
|
||||
.bind("func_decl")));
|
||||
|
||||
// Match the cases where we know that the result is a 'Duration' and the
|
||||
// first argument is a 'Time'. Just knowing the type of the first operand
|
||||
// is not sufficient, since the second operand could be either a 'Time' or
|
||||
// a 'Duration'. If we know the result is a 'Duration', we can then infer
|
||||
// that the second operand must be a 'Time'.
|
||||
auto CallMatcher =
|
||||
callExpr(
|
||||
callee(functionDecl(hasName(getDurationFactoryForScale(*Scale)))),
|
||||
hasArgument(0, binaryOperator(hasOperatorName("-"),
|
||||
hasLHS(TimeInverseMatcher))
|
||||
.bind("binop")))
|
||||
.bind("outer_call");
|
||||
Finder->addMatcher(CallMatcher, this);
|
||||
|
||||
// Match cases where we know the second operand is a 'Time'. Since
|
||||
// subtracting a 'Time' from a 'Duration' is not defined, in these cases,
|
||||
// we always know the first operand is a 'Time' if the second is a 'Time'.
|
||||
auto OperandMatcher =
|
||||
binaryOperator(hasOperatorName("-"), hasRHS(TimeInverseMatcher))
|
||||
.bind("binop");
|
||||
Finder->addMatcher(OperandMatcher, this);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeSubtractionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop");
|
||||
std::string InverseName =
|
||||
Result.Nodes.getNodeAs<FunctionDecl>("func_decl")->getNameAsString();
|
||||
if (InsideMacroDefinition(Result, BinOp->getSourceRange()))
|
||||
return;
|
||||
|
||||
llvm::Optional<DurationScale> Scale = getScaleForTimeInverse(InverseName);
|
||||
if (!Scale)
|
||||
return;
|
||||
|
||||
const auto *OuterCall = Result.Nodes.getNodeAs<CallExpr>("outer_call");
|
||||
if (OuterCall) {
|
||||
if (InsideMacroDefinition(Result, OuterCall->getSourceRange()))
|
||||
return;
|
||||
|
||||
// We're working with the first case of matcher, and need to replace the
|
||||
// entire 'Duration' factory call. (Which also means being careful about
|
||||
// our order-of-operations and optionally putting in some parenthesis.
|
||||
bool NeedParens = parensRequired(Result, OuterCall);
|
||||
|
||||
emitDiagnostic(
|
||||
OuterCall,
|
||||
(llvm::Twine(NeedParens ? "(" : "") +
|
||||
rewriteExprFromNumberToTime(Result, *Scale, BinOp->getLHS()) + " - " +
|
||||
rewriteExprFromNumberToTime(Result, *Scale, BinOp->getRHS()) +
|
||||
(NeedParens ? ")" : ""))
|
||||
.str());
|
||||
} else {
|
||||
// We're working with the second case of matcher, and either just need to
|
||||
// change the arguments, or perhaps remove an outer function call. In the
|
||||
// latter case (addressed first), we also need to worry about parenthesis.
|
||||
const auto *MaybeCallArg = selectFirst<const CallExpr>(
|
||||
"arg", match(expr(hasAncestor(
|
||||
callExpr(callee(functionDecl(hasName(
|
||||
getDurationFactoryForScale(*Scale)))))
|
||||
.bind("arg"))),
|
||||
*BinOp, *Result.Context));
|
||||
if (MaybeCallArg && MaybeCallArg->getArg(0)->IgnoreImpCasts() == BinOp &&
|
||||
!InsideMacroDefinition(Result, MaybeCallArg->getSourceRange())) {
|
||||
// Handle the case where the matched expression is inside a call which
|
||||
// converts it from the inverse to a Duration. In this case, we replace
|
||||
// the outer with just the subtraction expresison, which gives the right
|
||||
// type and scale, taking care again about parenthesis.
|
||||
bool NeedParens = parensRequired(Result, MaybeCallArg);
|
||||
|
||||
emitDiagnostic(
|
||||
MaybeCallArg,
|
||||
(llvm::Twine(NeedParens ? "(" : "") +
|
||||
rewriteExprFromNumberToTime(Result, *Scale, BinOp->getLHS()) +
|
||||
" - " +
|
||||
rewriteExprFromNumberToTime(Result, *Scale, BinOp->getRHS()) +
|
||||
(NeedParens ? ")" : ""))
|
||||
.str());
|
||||
} else {
|
||||
// In the last case, just convert the arguments and wrap the result in
|
||||
// the correct inverse function.
|
||||
emitDiagnostic(
|
||||
BinOp,
|
||||
(llvm::Twine(
|
||||
getDurationInverseForScale(*Scale).second.str().substr(2)) +
|
||||
"(" + rewriteExprFromNumberToTime(Result, *Scale, BinOp->getLHS()) +
|
||||
" - " +
|
||||
rewriteExprFromNumberToTime(Result, *Scale, BinOp->getRHS()) + ")")
|
||||
.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace abseil
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,38 @@
|
|||
//===--- TimeSubtractionCheck.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_TIMESUBTRACTIONCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMESUBTRACTIONCHECK_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace abseil {
|
||||
|
||||
/// Finds and fixes `absl::Time` subtraction expressions to do subtraction
|
||||
/// in the time domain instead of the numeric domain.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-time-subtraction.html
|
||||
class TimeSubtractionCheck : public ClangTidyCheck {
|
||||
public:
|
||||
TimeSubtractionCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
|
||||
private:
|
||||
void emitDiagnostic(const Expr* Node, llvm::StringRef Replacement);
|
||||
};
|
||||
|
||||
} // namespace abseil
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_TIMESUBTRACTIONCHECK_H
|
|
@ -85,6 +85,12 @@ Improvements to clang-tidy
|
|||
Finds and fixes cases where ``absl::Duration`` values are being converted to
|
||||
numeric types and back again.
|
||||
|
||||
- New :doc:`abseil-time-subtraction
|
||||
<clang-tidy/checks/abseil-time-subtraction>` check.
|
||||
|
||||
Finds and fixes ``absl::Time`` subtraction expressions to do subtraction
|
||||
in the Time domain instead of the numeric domain.
|
||||
|
||||
- New :doc:`google-readability-avoid-underscore-in-googletest-name
|
||||
<clang-tidy/checks/google-readability-avoid-underscore-in-googletest-name>`
|
||||
check.
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
.. title:: clang-tidy - abseil-time-subtraction
|
||||
|
||||
abseil-time-subtraction
|
||||
=======================
|
||||
|
||||
Finds and fixes ``absl::Time`` subtraction expressions to do subtraction
|
||||
in the Time domain instead of the numeric domain.
|
||||
|
||||
There are two cases of Time subtraction in which deduce additional type
|
||||
information:
|
||||
- When the result is an ``absl::Duration`` and the first argument is an
|
||||
``absl::Time``.
|
||||
- When the second argument is a ``absl::Time``.
|
||||
|
||||
In the first case, we must know the result of the operation, since without that
|
||||
the second operand could be either an ``absl::Time`` or an ``absl::Duration``.
|
||||
In the second case, the first operand *must* be an ``absl::Time``, because
|
||||
subtracting an ``absl::Time`` from an ``absl::Duration`` is not defined.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: c++
|
||||
int x;
|
||||
absl::Time t;
|
||||
|
||||
// Original - absl::Duration result and first operand is a absl::Time.
|
||||
absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x);
|
||||
|
||||
// Suggestion - Perform subtraction in the Time domain instead.
|
||||
absl::Duration d = t - absl::FromUnixSeconds(x);
|
||||
|
||||
|
||||
// Original - Second operand is an absl::Time.
|
||||
int i = x - absl::ToUnixSeconds(t);
|
||||
|
||||
// Suggestion - Perform subtraction in the Time domain instead.
|
||||
int i = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t);
|
|
@ -18,6 +18,7 @@ Clang-Tidy Checks
|
|||
abseil-redundant-strcat-calls
|
||||
abseil-str-cat-append
|
||||
abseil-string-find-startswith
|
||||
abseil-time-subtraction
|
||||
abseil-upgrade-duration-conversions
|
||||
android-cloexec-accept
|
||||
android-cloexec-accept4
|
||||
|
|
|
@ -70,6 +70,8 @@ Time FromUnixMillis(int64_t);
|
|||
Time FromUnixMicros(int64_t);
|
||||
Time FromUnixNanos(int64_t);
|
||||
|
||||
Time Now();
|
||||
|
||||
// Relational Operators
|
||||
constexpr bool operator<(Duration lhs, Duration rhs);
|
||||
constexpr bool operator>(Duration lhs, Duration rhs);
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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) absl::Hours(z)
|
||||
d = HOURS(absl::ToUnixHours(t) - x);
|
||||
#undef HOURS
|
||||
|
||||
// This should match the expression inside the macro invocation.
|
||||
#define SECONDS(z) absl::Seconds(z)
|
||||
d = SECONDS(x - absl::ToUnixSeconds(t));
|
||||
// CHECK-MESSAGES: [[@LINE-1]]:15: warning: perform subtraction in the time domain [abseil-time-subtraction]
|
||||
// CHECK-FIXES: SECONDS(absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t))
|
||||
#undef SECONDS
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void func(absl::Time t, T x) {
|
||||
absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x);
|
||||
// CHECK-MESSAGES: [[@LINE-1]]:22: warning: perform subtraction in the time domain [abseil-time-subtraction]
|
||||
// CHECK-FIXES: absl::Duration d = t - absl::FromUnixSeconds(x);
|
||||
}
|
||||
|
||||
void g() {
|
||||
func(absl::Now(), 5);
|
||||
}
|
||||
|
||||
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 absl::FromUnixSeconds(x) - t;
|
||||
}
|
Loading…
Reference in New Issue