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" 22 namespace performance {
29 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
30 return (ICE->getCastKind() != CK_NoOp) ||
36 void ImplicitConversionInLoopCheck::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 ImplicitConversionInLoopCheck::check(
59 const MatchFinder::MatchResult &Result) {
60 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"faulty-var");
61 const auto *Init = Result.Nodes.getNodeAs<Expr>(
"init");
62 const auto *OperatorCall =
63 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"operator-call");
65 if (
const auto *Cleanup = dyn_cast<ExprWithCleanups>(Init))
66 Init = Cleanup->getSubExpr();
68 const auto *Materialized = dyn_cast<MaterializeTemporaryExpr>(Init);
77 ReportAndFix(Result.Context, VD, OperatorCall);
80 void ImplicitConversionInLoopCheck::ReportAndFix(
81 const ASTContext *Context,
const VarDecl *VD,
82 const CXXOperatorCallExpr *OperatorCall) {
85 QualType ConstType = OperatorCall->getType().withConst();
86 QualType ConstRefType = Context->getLValueReferenceType(ConstType);
88 "the type of the loop variable %0 is different from the one returned " 89 "by the iterator and generates an implicit conversion; you can either " 90 "change the type to the matching one (%1 but 'const auto&' is always a " 91 "valid option) or remove the reference to make it explicit that you are " 92 "creating a new value";
93 diag(VD->getLocStart(),
Message) << VD << ConstRefType;
static const StringRef Message