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) {
50 cxxForRangeStmt(hasLoopVariable(
52 hasType(qualType(references(qualType(isConstQualified())))),
54 expr(anyOf(hasDescendant(
55 cxxOperatorCallExpr().bind(
"operator-call")),
56 hasDescendant(unaryOperator(hasOperatorName(
"*"))
57 .bind(
"operator-call"))))
59 .bind(
"faulty-var"))),
63 void ImplicitConversionInLoopCheck::check(
64 const MatchFinder::MatchResult &Result) {
65 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"faulty-var");
66 const auto *Init = Result.Nodes.getNodeAs<Expr>(
"init");
67 const auto *OperatorCall =
68 Result.Nodes.getNodeAs<Expr>(
"operator-call");
70 if (
const auto *Cleanup = dyn_cast<ExprWithCleanups>(Init))
71 Init = Cleanup->getSubExpr();
73 const auto *Materialized = dyn_cast<MaterializeTemporaryExpr>(Init);
82 ReportAndFix(Result.Context, VD, OperatorCall);
85 void ImplicitConversionInLoopCheck::ReportAndFix(
86 const ASTContext *Context,
const VarDecl *VD,
87 const Expr *OperatorCall) {
90 QualType ConstType = OperatorCall->getType().withConst();
91 QualType ConstRefType = Context->getLValueReferenceType(ConstType);
93 "the type of the loop variable %0 is different from the one returned " 94 "by the iterator and generates an implicit conversion; you can either " 95 "change the type to the matching one (%1 but 'const auto&' is always a " 96 "valid option) or remove the reference to make it explicit that you are " 97 "creating a new value";
98 diag(VD->getBeginLoc(),
Message) << VD << ConstRefType;
constexpr llvm::StringLiteral Message
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//