diff options
Diffstat (limited to 'clang-tidy/abseil/DurationRewriter.cpp')
-rw-r--r-- | clang-tidy/abseil/DurationRewriter.cpp | 121 |
1 files changed, 112 insertions, 9 deletions
diff --git a/clang-tidy/abseil/DurationRewriter.cpp b/clang-tidy/abseil/DurationRewriter.cpp index ed648897..3466cdbb 100644 --- a/clang-tidy/abseil/DurationRewriter.cpp +++ b/clang-tidy/abseil/DurationRewriter.cpp @@ -1,9 +1,8 @@ //===--- DurationRewriter.cpp - clang-tidy --------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -38,7 +37,7 @@ truncateIfIntegral(const FloatingLiteral &FloatLiteral) { } const std::pair<llvm::StringRef, llvm::StringRef> & -getInverseForScale(DurationScale Scale) { +getDurationInverseForScale(DurationScale Scale) { static const llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>, DurationScale2IndexFunctor> InverseMap = []() { @@ -72,7 +71,7 @@ static llvm::Optional<std::string> rewriteInverseDurationCall(const MatchFinder::MatchResult &Result, DurationScale Scale, const Expr &Node) { const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions = - getInverseForScale(Scale); + getDurationInverseForScale(Scale); if (const auto *MaybeCallArg = selectFirst<const Expr>( "e", match(callExpr(callee(functionDecl(hasAnyName( @@ -85,8 +84,24 @@ 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 getFactoryForScale(DurationScale Scale) { +llvm::StringRef getDurationFactoryForScale(DurationScale Scale) { switch (Scale) { case DurationScale::Hours: return "absl::Hours"; @@ -104,6 +119,43 @@ llvm::StringRef getFactoryForScale(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) { + 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 &Result, const Expr &Node) { auto ZeroMatcher = @@ -176,7 +228,7 @@ std::string simplifyDurationFactoryArg(const MatchFinder::MatchResult &Result, return tooling::fixit::getText(Node, *Result.Context).str(); } -llvm::Optional<DurationScale> getScaleForInverse(llvm::StringRef Name) { +llvm::Optional<DurationScale> getScaleForDurationInverse(llvm::StringRef Name) { static const llvm::StringMap<DurationScale> ScaleMap( {{"ToDoubleHours", DurationScale::Hours}, {"ToInt64Hours", DurationScale::Hours}, @@ -198,6 +250,22 @@ llvm::Optional<DurationScale> getScaleForInverse(llvm::StringRef Name) { return ScaleIter->second; } +llvm::Optional<DurationScale> getScaleForTimeInverse(llvm::StringRef Name) { + static const llvm::StringMap<DurationScale> 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 &Result, DurationScale Scale, const Expr *Node) { @@ -211,11 +279,46 @@ std::string rewriteExprFromNumberToDuration( if (IsLiteralZero(Result, RootNode)) return std::string("absl::ZeroDuration()"); - return (llvm::Twine(getFactoryForScale(Scale)) + "(" + + return (llvm::Twine(getDurationFactoryForScale(Scale)) + "(" + simplifyDurationFactoryArg(Result, RootNode) + ")") .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 isInMacro(const MatchFinder::MatchResult &Result, const Expr *E) { + if (!E->getBeginLoc().isMacroID()) + return false; + + 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(); +} + } // namespace abseil } // namespace tidy } // namespace clang |