100 const auto *InitDeclStmt = dyn_cast_or_null<DeclStmt>(If->getInit());
103 if (InitDeclStmt->isSingleDecl()) {
104 const Decl *InitDecl = InitDeclStmt->getSingleDecl();
105 assert(isa<VarDecl>(InitDecl) &&
"SingleDecl must be a VarDecl");
106 return findUsage(If->getElse(), InitDecl);
128 const Stmt *Else, SourceLocation ElseLoc) {
129 auto Remap = [&](SourceLocation Loc) {
130 return Context.getSourceManager().getExpansionLoc(Loc);
133 if (
const auto *CS = dyn_cast<CompoundStmt>(Else)) {
134 Diag << tooling::fixit::createRemoval(ElseLoc)
135 << tooling::fixit::createRemoval(Remap(CS->getLBracLoc()))
136 << tooling::fixit::createRemoval(Remap(CS->getRBracLoc()));
138 Diag << tooling::fixit::createRemoval(Remap(ElseLoc));
162 const auto InterruptsControlFlow =
163 stmt(anyOf(returnStmt(), continueStmt(), breakStmt(), cxxThrowExpr(),
164 callExpr(callee(functionDecl(isNoReturn())))));
166 const auto IfWithInterruptingThenElse =
167 ifStmt(unless(isConstexpr()), unless(isConsteval()),
169 hasElse(stmt().bind(
"else")))
172 Finder->addMatcher(compoundStmt(forEach(stripLabelLikeStatements(
173 IfWithInterruptingThenElse)))
180 const SourceManager &SM, SourceLocation StartLoc, SourceLocation EndLoc) {
181 const SourceLocation ExpandedStartLoc = SM.getExpansionLoc(StartLoc);
182 const SourceLocation ExpandedEndLoc = SM.getExpansionLoc(EndLoc);
183 if (!SM.isWrittenInSameFile(ExpandedStartLoc, ExpandedEndLoc))
187 if (ExpandedStartLoc == ExpandedEndLoc)
190 assert(ExpandedStartLoc < ExpandedEndLoc);
192 auto Iter = ConditionalBranchMap.find(SM.getFileID(ExpandedEndLoc));
194 if (Iter == ConditionalBranchMap.end() || Iter->getSecond().empty())
199 assert(llvm::is_sorted(ConditionalBranches,
200 [](
const SourceRange &LHS,
const SourceRange &RHS) {
201 return LHS.getEnd() < RHS.getEnd();
206 llvm::lower_bound(ConditionalBranches, ExpandedStartLoc,
207 [](
const SourceRange &LHS,
const SourceLocation &RHS) {
208 return LHS.getEnd() < RHS;
210 const auto *End = ConditionalBranches.end();
211 for (; Begin != End && Begin->getEnd() < ExpandedEndLoc; ++Begin)
212 if (Begin->getBegin() < ExpandedStartLoc)
232 const auto *If = Result.Nodes.getNodeAs<IfStmt>(
"if");
233 const auto *Else = Result.Nodes.getNodeAs<Stmt>(
"else");
234 const auto *OuterScope = Result.Nodes.getNodeAs<CompoundStmt>(
"cs");
236 const SourceLocation ElseLoc = If->getElseLoc();
239 PPConditionals, *Result.SourceManager, Interrupt->getBeginLoc(),
243 const bool IsLastInScope = OuterScope->body_back() == If;
247 if (WarnOnUnfixable) {
255 if (!WarnOnConditionVariables)
261 << ControlFlowInterrupter
262 << SourceRange(ElseLoc);
264 Diag << tooling::fixit::createReplacement(
265 SourceRange(If->getIfLoc()),
266 (tooling::fixit::getText(*If->getInit(), *Result.Context) +
269 << tooling::fixit::createRemoval(If->getInit()->getSourceRange());
271 const DeclStmt *VDeclStmt = If->getConditionVariableDeclStmt();
272 const VarDecl *VDecl = If->getConditionVariable();
273 const std::string Repl =
274 (tooling::fixit::getText(*VDeclStmt, *Result.Context) +
276 tooling::fixit::getText(If->getIfLoc(), *Result.Context))
278 Diag << tooling::fixit::createReplacement(SourceRange(If->getIfLoc()),
280 << tooling::fixit::createReplacement(VDeclStmt->getSourceRange(),
283 }
else if (WarnOnUnfixable) {
291 if (!WarnOnConditionVariables)
297 << ControlFlowInterrupter
298 << SourceRange(ElseLoc);
299 Diag << tooling::fixit::createReplacement(
300 SourceRange(If->getIfLoc()),
301 (tooling::fixit::getText(*If->getInit(), *Result.Context) +
303 tooling::fixit::getText(If->getIfLoc(), *Result.Context))
305 << tooling::fixit::createRemoval(If->getInit()->getSourceRange());
307 }
else if (WarnOnUnfixable) {
315 << ControlFlowInterrupter << SourceRange(ElseLoc);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.