11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
21 void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) {
36 0, expr(hasType(cxxRecordDecl(hasName(
"::absl::Duration"))))),
37 hasArgument(1, expr().bind(
"arg")),
39 hasParent(functionTemplateDecl()),
40 unless(hasTemplateArgument(0, refersToType(builtinType()))),
41 hasAnyName(
"operator*=",
"operator/="))))
50 ofClass(cxxRecordDecl(hasName(
"::absl::Duration"))),
51 hasParent(functionTemplateDecl()),
52 unless(hasTemplateArgument(0, refersToType(builtinType()))),
53 hasAnyName(
"operator*=",
"operator/="))),
54 argumentCountIs(1), hasArgument(0, expr().bind(
"arg")))
62 callExpr(callee(functionDecl(
63 hasParent(functionTemplateDecl()),
64 unless(hasTemplateArgument(0, refersToType(builtinType()))),
65 hasAnyName(
"::absl::operator*",
"::absl::operator/"))),
67 hasArgument(0, expr(hasType(
68 cxxRecordDecl(hasName(
"::absl::Duration"))))),
69 hasArgument(1, expr().bind(
"arg")))
76 callExpr(callee(functionDecl(
77 hasParent(functionTemplateDecl()),
78 unless(hasTemplateArgument(0, refersToType(builtinType()))),
79 hasName(
"::absl::operator*"))),
80 argumentCountIs(2), hasArgument(0, expr().bind(
"arg")),
81 hasArgument(1, expr(hasType(
82 cxxRecordDecl(hasName(
"::absl::Duration"))))))
104 ast_type_traits::TK_AsIs,
105 implicitCastExpr(anyOf(hasCastKind(CK_UserDefinedConversion),
106 has(implicitCastExpr(
107 hasCastKind(CK_UserDefinedConversion)))),
110 DurationFactoryFunction(),
111 unless(hasParent(functionTemplateDecl())))),
112 hasArgument(0, expr().bind(
"arg")))))
117 void UpgradeDurationConversionsCheck::check(
118 const MatchFinder::MatchResult &Result) {
119 const llvm::StringRef
Message =
120 "implicit conversion to 'int64_t' is deprecated in this context; use an "
121 "explicit cast instead";
123 TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
125 const auto *ArgExpr = Result.Nodes.getNodeAs<Expr>(
"arg");
126 SourceLocation
Loc = ArgExpr->getBeginLoc();
128 const auto *OuterExpr = Result.Nodes.getNodeAs<Expr>(
"OuterExpr");
130 if (!
match(isInTemplateInstantiation(), *OuterExpr, *Result.Context)
132 if (MatchedTemplateLocations.count(
Loc.getRawEncoding()) == 0) {
145 internal::Matcher<Stmt> IsInsideTemplate =
146 hasAncestor(decl(anyOf(classTemplateDecl(), functionTemplateDecl())));
147 if (!
match(IsInsideTemplate, *ArgExpr, *Result.Context).empty())
148 MatchedTemplateLocations.insert(
Loc.getRawEncoding());
151 CharSourceRange SourceRange = Lexer::makeFileCharRange(
152 CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
153 *Result.SourceManager, Result.Context->getLangOpts());
154 if (SourceRange.isInvalid())
159 Diag << FixItHint::CreateInsertion(SourceRange.getBegin(),
160 "static_cast<int64_t>(")
161 << FixItHint::CreateInsertion(SourceRange.getEnd(),
")");