11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/Lex/Lexer.h"
21 namespace performance {
28 if (
const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
29 return (ICE->getCastKind() != CK_NoOp) ||
35 void ImplicitConversionInLoopCheck::registerMatchers(MatchFinder *Finder) {
51 ast_type_traits::TK_AsIs,
52 cxxForRangeStmt(hasLoopVariable(
54 hasType(qualType(references(qualType(isConstQualified())))),
58 cxxOperatorCallExpr().bind(
"operator-call")),
59 hasDescendant(unaryOperator(hasOperatorName(
"*"))
60 .bind(
"operator-call"))))
62 .bind(
"faulty-var")))),
66 void ImplicitConversionInLoopCheck::check(
67 const MatchFinder::MatchResult &Result) {
68 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"faulty-var");
69 const auto *Init = Result.Nodes.getNodeAs<Expr>(
"init");
70 const auto *OperatorCall =
71 Result.Nodes.getNodeAs<Expr>(
"operator-call");
73 if (
const auto *Cleanup = dyn_cast<ExprWithCleanups>(Init))
74 Init = Cleanup->getSubExpr();
76 const auto *Materialized = dyn_cast<MaterializeTemporaryExpr>(Init);
85 ReportAndFix(Result.Context, VD, OperatorCall);
88 void ImplicitConversionInLoopCheck::ReportAndFix(
89 const ASTContext *Context,
const VarDecl *VD,
90 const Expr *OperatorCall) {
93 QualType ConstType = OperatorCall->getType().withConst();
94 QualType ConstRefType = Context->getLValueReferenceType(ConstType);
96 "the type of the loop variable %0 is different from the one returned "
97 "by the iterator and generates an implicit conversion; you can either "
98 "change the type to the matching one (%1 but 'const auto&' is always a "
99 "valid option) or remove the reference to make it explicit that you are "
100 "creating a new value";
101 diag(VD->getBeginLoc(),
Message) << VD << ConstRefType;