12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/ASTMatchers/ASTMatchers.h"
16 #include "clang/Lex/Lexer.h"
18 using namespace clang::ast_matchers;
22 namespace performance {
29 bool IsNonTrivialImplicitCast(
const Stmt *ST) {
30 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
31 return (ICE->getCastKind() != CK_NoOp) ||
32 IsNonTrivialImplicitCast(ICE->getSubExpr());
38 void ImplicitCastInLoopCheck::registerMatchers(MatchFinder *
Finder) {
49 cxxForRangeStmt(hasLoopVariable(
50 varDecl(hasType(qualType(references(qualType(isConstQualified())))),
51 hasInitializer(expr(hasDescendant(cxxOperatorCallExpr().bind(
54 .bind(
"faulty-var"))),
58 void ImplicitCastInLoopCheck::check(
const MatchFinder::MatchResult &Result) {
59 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"faulty-var");
60 const auto *Init = Result.Nodes.getNodeAs<Expr>(
"init");
61 const auto *OperatorCall =
62 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"operator-call");
64 if (
const auto *Cleanup = dyn_cast<ExprWithCleanups>(Init))
65 Init = Cleanup->getSubExpr();
67 const auto *Materialized = dyn_cast<MaterializeTemporaryExpr>(Init);
75 if (IsNonTrivialImplicitCast(Materialized->getTemporary()))
76 ReportAndFix(Result.Context, VD, OperatorCall);
79 void ImplicitCastInLoopCheck::ReportAndFix(
80 const ASTContext *
Context,
const VarDecl *VD,
81 const CXXOperatorCallExpr *OperatorCall) {
84 QualType ConstType = OperatorCall->getType().withConst();
85 QualType ConstRefType = Context->getLValueReferenceType(ConstType);
87 "the type of the loop variable %0 is different from the one returned "
88 "by the iterator and generates an implicit cast; you can either "
89 "change the type to the correct one (%1 but 'const auto&' is always a "
90 "valid option) or remove the reference to make it explicit that you are "
91 "creating a new value";
92 diag(VD->getLocStart(),
Message) << VD << ConstRefType;
std::unique_ptr< ast_matchers::MatchFinder > Finder
static const StringRef Message
ClangTidyContext & Context