| 1 | //===--- DurationRewriter.h - clang-tidy ------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONREWRITER_H |
| 10 | #define |
| 11 | |
| 12 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 13 | #include "clang/ASTMatchers/ASTMatchers.h" |
| 14 | #include <cinttypes> |
| 15 | #include <optional> |
| 16 | |
| 17 | namespace clang::tidy::abseil { |
| 18 | |
| 19 | /// Duration factory and conversion scales |
| 20 | enum class DurationScale : std::uint8_t { |
| 21 | Hours = 0, |
| 22 | Minutes, |
| 23 | Seconds, |
| 24 | Milliseconds, |
| 25 | Microseconds, |
| 26 | Nanoseconds, |
| 27 | }; |
| 28 | |
| 29 | /// Given a `Scale`, return the appropriate factory function call for |
| 30 | /// constructing a `Duration` for that scale. |
| 31 | llvm::StringRef getDurationFactoryForScale(DurationScale Scale); |
| 32 | |
| 33 | /// Given a 'Scale', return the appropriate factory function call for |
| 34 | /// constructing a `Time` for that scale. |
| 35 | llvm::StringRef getTimeFactoryForScale(DurationScale Scale); |
| 36 | |
| 37 | // Determine if `Node` represents a literal floating point or integral zero. |
| 38 | bool isLiteralZero(const ast_matchers::MatchFinder::MatchResult &Result, |
| 39 | const Expr &Node); |
| 40 | |
| 41 | /// Possibly strip a floating point cast expression. |
| 42 | /// |
| 43 | /// If `Node` represents an explicit cast to a floating point type, return |
| 44 | /// the textual context of the cast argument, otherwise `std::nullopt`. |
| 45 | std::optional<std::string> |
| 46 | stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result, |
| 47 | const Expr &Node); |
| 48 | |
| 49 | /// Possibly remove the fractional part of a floating point literal. |
| 50 | /// |
| 51 | /// If `Node` represents a floating point literal with a zero fractional part, |
| 52 | /// return the textual context of the integral part, otherwise `std::nullopt`. |
| 53 | std::optional<std::string> |
| 54 | stripFloatLiteralFraction(const ast_matchers::MatchFinder::MatchResult &Result, |
| 55 | const Expr &Node); |
| 56 | |
| 57 | /// Possibly further simplify a duration factory function's argument, without |
| 58 | /// changing the scale of the factory function. Return that simplification or |
| 59 | /// the text of the argument if no simplification is possible. |
| 60 | std::string |
| 61 | simplifyDurationFactoryArg(const ast_matchers::MatchFinder::MatchResult &Result, |
| 62 | const Expr &Node); |
| 63 | |
| 64 | /// Given the name of an inverse Duration function (e.g., `ToDoubleSeconds`), |
| 65 | /// return its `DurationScale`, or `std::nullopt` if a match is not found. |
| 66 | std::optional<DurationScale> getScaleForDurationInverse(llvm::StringRef Name); |
| 67 | |
| 68 | /// Given the name of an inverse Time function (e.g., `ToUnixSeconds`), |
| 69 | /// return its `DurationScale`, or `std::nullopt` if a match is not found. |
| 70 | std::optional<DurationScale> getScaleForTimeInverse(llvm::StringRef Name); |
| 71 | |
| 72 | /// Given a `Scale` return the fully qualified inverse functions for it. |
| 73 | /// The first returned value is the inverse for `double`, and the second |
| 74 | /// returned value is the inverse for `int64`. |
| 75 | const std::pair<llvm::StringRef, llvm::StringRef> & |
| 76 | getDurationInverseForScale(DurationScale Scale); |
| 77 | |
| 78 | /// Returns the Time inverse function name for a given `Scale`. |
| 79 | llvm::StringRef getTimeInverseForScale(DurationScale Scale); |
| 80 | |
| 81 | /// Assuming `Node` has type `double` or `int` representing a time interval of |
| 82 | /// `Scale`, return the expression to make it a suitable `Duration`. |
| 83 | std::string rewriteExprFromNumberToDuration( |
| 84 | const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale, |
| 85 | const Expr *Node); |
| 86 | |
| 87 | /// Assuming `Node` has a type `int` representing a time instant of `Scale` |
| 88 | /// since The Epoch, return the expression to make it a suitable `Time`. |
| 89 | std::string rewriteExprFromNumberToTime( |
| 90 | const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale, |
| 91 | const Expr *Node); |
| 92 | |
| 93 | /// Return `false` if `E` is a either: not a macro at all; or an argument to |
| 94 | /// one. In the both cases, we often want to do the transformation. |
| 95 | bool isInMacro(const ast_matchers::MatchFinder::MatchResult &Result, |
| 96 | const Expr *E); |
| 97 | |
| 98 | AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<FunctionDecl>, |
| 99 | DurationConversionFunction) { |
| 100 | using namespace clang::ast_matchers; |
| 101 | return functionDecl( |
| 102 | hasAnyName("::absl::ToDoubleHours" , "::absl::ToDoubleMinutes" , |
| 103 | "::absl::ToDoubleSeconds" , "::absl::ToDoubleMilliseconds" , |
| 104 | "::absl::ToDoubleMicroseconds" , "::absl::ToDoubleNanoseconds" , |
| 105 | "::absl::ToInt64Hours" , "::absl::ToInt64Minutes" , |
| 106 | "::absl::ToInt64Seconds" , "::absl::ToInt64Milliseconds" , |
| 107 | "::absl::ToInt64Microseconds" , "::absl::ToInt64Nanoseconds" )); |
| 108 | } |
| 109 | |
| 110 | AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<FunctionDecl>, |
| 111 | DurationFactoryFunction) { |
| 112 | using namespace clang::ast_matchers; |
| 113 | return functionDecl(hasAnyName("::absl::Nanoseconds" , "::absl::Microseconds" , |
| 114 | "::absl::Milliseconds" , "::absl::Seconds" , |
| 115 | "::absl::Minutes" , "::absl::Hours" )); |
| 116 | } |
| 117 | |
| 118 | AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<FunctionDecl>, |
| 119 | TimeConversionFunction) { |
| 120 | using namespace clang::ast_matchers; |
| 121 | return functionDecl(hasAnyName( |
| 122 | "::absl::ToUnixHours" , "::absl::ToUnixMinutes" , "::absl::ToUnixSeconds" , |
| 123 | "::absl::ToUnixMillis" , "::absl::ToUnixMicros" , "::absl::ToUnixNanos" )); |
| 124 | } |
| 125 | |
| 126 | AST_MATCHER_FUNCTION_P(ast_matchers::internal::Matcher<Stmt>, |
| 127 | comparisonOperatorWithCallee, |
| 128 | ast_matchers::internal::Matcher<Decl>, funcDecl) { |
| 129 | using namespace clang::ast_matchers; |
| 130 | return binaryOperator( |
| 131 | anyOf(hasOperatorName(Name: ">" ), hasOperatorName(Name: ">=" ), hasOperatorName(Name: "==" ), |
| 132 | hasOperatorName(Name: "<=" ), hasOperatorName(Name: "<" )), |
| 133 | hasEitherOperand(InnerMatcher: ignoringImpCasts(InnerMatcher: callExpr(callee(InnerMatcher: funcDecl))))); |
| 134 | } |
| 135 | |
| 136 | } // namespace clang::tidy::abseil |
| 137 | |
| 138 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONREWRITER_H |
| 139 | |