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 | |