77 const auto NonMemberMatcher = expr(ignoringImplicit(ignoringParenImpCasts(
79 hasParent(stmt(optionally(hasParent(stmtExpr().bind(
"stexpr"))))
81 unless(hasAncestor(classTemplateDecl())),
82 callee(functionDecl(hasName(
"empty"), unless(returns(voidType())))))
84 const auto MemberMatcher =
85 expr(ignoringImplicit(ignoringParenImpCasts(cxxMemberCallExpr(
86 hasParent(stmt(optionally(hasParent(stmtExpr().bind(
"stexpr"))))
88 callee(cxxMethodDecl(hasName(
"empty"),
89 unless(returns(voidType()))))))))
92 Finder->addMatcher(MemberMatcher,
this);
93 Finder->addMatcher(NonMemberMatcher,
this);
98 if (Result.Nodes.getNodeAs<Expr>(
"parent"))
101 const auto *PParentStmtExpr = Result.Nodes.getNodeAs<Expr>(
"stexpr");
102 const auto *ParentCompStmt = Result.Nodes.getNodeAs<CompoundStmt>(
"parent");
103 const auto *ParentCond =
getCondition(Result.Nodes,
"parent");
104 const auto *ParentReturnStmt = Result.Nodes.getNodeAs<ReturnStmt>(
"parent");
106 if (
const auto *MemberCall =
107 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"empty")) {
109 if (ParentCond == MemberCall->getExprStmt())
113 if (PParentStmtExpr && ParentCompStmt &&
114 ParentCompStmt->body_back() == MemberCall->getExprStmt())
117 if (ParentReturnStmt)
120 const SourceLocation MemberLoc = MemberCall->getBeginLoc();
121 const SourceLocation ReplacementLoc = MemberCall->getExprLoc();
122 const SourceRange ReplacementRange =
123 SourceRange(ReplacementLoc, ReplacementLoc);
125 ASTContext &Context = MemberCall->getRecordDecl()->getASTContext();
126 const DeclarationName Name =
127 Context.DeclarationNames.getIdentifier(&Context.Idents.get(
"clear"));
129 auto Candidates = HeuristicResolver(Context).lookupDependentName(
130 MemberCall->getRecordDecl(), Name, [](
const NamedDecl *ND) {
131 return isa<CXXMethodDecl>(ND) &&
132 llvm::cast<CXXMethodDecl>(ND)->getMinRequiredArguments() ==
134 !llvm::cast<CXXMethodDecl>(ND)->isConst();
137 const bool HasClear = !Candidates.empty();
139 const auto *Clear = llvm::cast<CXXMethodDecl>(Candidates.at(0));
140 const QualType RangeType =
141 MemberCall->getImplicitObjectArgument()->getType();
142 const bool QualifierIncompatible =
143 (!Clear->isVolatile() && RangeType.isVolatileQualified()) ||
144 RangeType.isConstQualified();
145 if (!QualifierIncompatible) {
147 "ignoring the result of 'empty()'; did you mean 'clear()'? ")
148 << FixItHint::CreateReplacement(ReplacementRange,
"clear");
153 diag(MemberLoc,
"ignoring the result of 'empty()'");
155 }
else if (
const auto *NonMemberCall =
156 Result.Nodes.getNodeAs<CallExpr>(
"empty")) {
157 if (ParentCond == NonMemberCall->getExprStmt())
159 if (PParentStmtExpr && ParentCompStmt &&
160 ParentCompStmt->body_back() == NonMemberCall->getExprStmt())
162 if (ParentReturnStmt)
164 if (NonMemberCall->getNumArgs() != 1)
167 const SourceLocation NonMemberLoc = NonMemberCall->getExprLoc();
168 const SourceLocation NonMemberEndLoc = NonMemberCall->getEndLoc();
170 const Expr *Arg = NonMemberCall->getArg(0);
171 CXXRecordDecl *ArgRecordDecl = Arg->getType()->getAsCXXRecordDecl();
172 if (ArgRecordDecl ==
nullptr)
175 ASTContext &Context = ArgRecordDecl->getASTContext();
176 const DeclarationName Name =
177 Context.DeclarationNames.getIdentifier(&Context.Idents.get(
"clear"));
179 auto Candidates = HeuristicResolver(Context).lookupDependentName(
180 ArgRecordDecl, Name, [](
const NamedDecl *ND) {
181 return isa<CXXMethodDecl>(ND) &&
182 llvm::cast<CXXMethodDecl>(ND)->getMinRequiredArguments() ==
184 !llvm::cast<CXXMethodDecl>(ND)->isConst();
187 const bool HasClear = !Candidates.empty();
190 const auto *Clear = llvm::cast<CXXMethodDecl>(Candidates.at(0));
191 const bool QualifierIncompatible =
192 (!Clear->isVolatile() && Arg->getType().isVolatileQualified()) ||
193 Arg->getType().isConstQualified();
194 if (!QualifierIncompatible) {
195 const std::string ReplacementText =
196 std::string(Lexer::getSourceText(
197 CharSourceRange::getTokenRange(Arg->getSourceRange()),
198 *Result.SourceManager, getLangOpts())) +
200 const SourceRange ReplacementRange =
201 SourceRange(NonMemberLoc, NonMemberEndLoc);
203 "ignoring the result of '%0'; did you mean 'clear()'?")
204 << llvm::dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
205 ->getQualifiedNameAsString()
206 << FixItHint::CreateReplacement(ReplacementRange, ReplacementText);
211 diag(NonMemberLoc,
"ignoring the result of '%0'")
212 << llvm::dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
213 ->getQualifiedNameAsString();