49static const DeclRefExpr *
findUsage(
const Stmt *Node, int64_t DeclIdentifier) {
52 if (
const auto *DeclRef = dyn_cast<DeclRefExpr>(Node)) {
53 if (DeclRef->getDecl()->getID() == DeclIdentifier)
56 for (
const Stmt *ChildNode : Node->children()) {
57 if (
const DeclRefExpr *Result =
findUsage(ChildNode, DeclIdentifier))
66 const llvm::ArrayRef<int64_t> &DeclIdentifiers) {
69 if (
const auto *DeclRef = dyn_cast<DeclRefExpr>(Node)) {
70 if (llvm::is_contained(DeclIdentifiers, DeclRef->getDecl()->getID()))
73 for (
const Stmt *ChildNode : Node->children()) {
74 if (
const DeclRefExpr *Result =
83 const auto *InitDeclStmt = dyn_cast_or_null<DeclStmt>(If->getInit());
86 if (InitDeclStmt->isSingleDecl()) {
87 const Decl *InitDecl = InitDeclStmt->getSingleDecl();
88 assert(isa<VarDecl>(InitDecl) &&
"SingleDecl must be a VarDecl");
89 return findUsage(If->getElse(), InitDecl->getID());
91 llvm::SmallVector<int64_t, 4> DeclIdentifiers;
92 for (
const Decl *ChildDecl : InitDeclStmt->decls()) {
93 assert(isa<VarDecl>(ChildDecl) &&
"Init Decls must be a VarDecl");
94 DeclIdentifiers.push_back(ChildDecl->getID());
116 const Stmt *Else, SourceLocation ElseLoc) {
117 auto Remap = [&](SourceLocation Loc) {
118 return Context.getSourceManager().getExpansionLoc(Loc);
120 auto TokLen = [&](SourceLocation Loc) {
121 return Lexer::MeasureTokenLength(Loc, Context.getSourceManager(),
122 Context.getLangOpts());
125 if (
const auto *CS = dyn_cast<CompoundStmt>(Else)) {
126 Diag << tooling::fixit::createRemoval(ElseLoc);
127 SourceLocation LBrace = CS->getLBracLoc();
128 SourceLocation RBrace = CS->getRBracLoc();
129 SourceLocation RangeStart =
130 Remap(LBrace).getLocWithOffset(TokLen(LBrace) + 1);
131 SourceLocation RangeEnd = Remap(RBrace).getLocWithOffset(-1);
133 llvm::StringRef Repl = Lexer::getSourceText(
134 CharSourceRange::getTokenRange(RangeStart, RangeEnd),
135 Context.getSourceManager(), Context.getLangOpts());
136 Diag << tooling::fixit::createReplacement(CS->getSourceRange(), Repl);
138 SourceLocation ElseExpandedLoc = Remap(ElseLoc);
139 SourceLocation EndLoc = Remap(Else->getEndLoc());
141 llvm::StringRef Repl = Lexer::getSourceText(
142 CharSourceRange::getTokenRange(
143 ElseExpandedLoc.getLocWithOffset(TokLen(ElseLoc) + 1), EndLoc),
144 Context.getSourceManager(), Context.getLangOpts());
145 Diag << tooling::fixit::createReplacement(
146 SourceRange(ElseExpandedLoc, EndLoc), Repl);
187 const SourceManager &SM, SourceLocation StartLoc, SourceLocation EndLoc) {
189 SourceLocation ExpandedStartLoc = SM.getExpansionLoc(StartLoc);
190 SourceLocation ExpandedEndLoc = SM.getExpansionLoc(EndLoc);
191 if (!SM.isWrittenInSameFile(ExpandedStartLoc, ExpandedEndLoc))
195 if (ExpandedStartLoc == ExpandedEndLoc)
198 assert(ExpandedStartLoc < ExpandedEndLoc);
200 auto Iter = ConditionalBranchMap.find(SM.getFileID(ExpandedEndLoc));
202 if (Iter == ConditionalBranchMap.end() || Iter->getSecond().empty())
205 const SmallVectorImpl<SourceRange> &ConditionalBranches = Iter->getSecond();
207 assert(llvm::is_sorted(ConditionalBranches,
208 [](
const SourceRange &LHS,
const SourceRange &RHS) {
209 return LHS.getEnd() < RHS.getEnd();
214 llvm::lower_bound(ConditionalBranches, ExpandedStartLoc,
215 [](
const SourceRange &LHS,
const SourceLocation &RHS) {
216 return LHS.getEnd() < RHS;
218 const auto *End = ConditionalBranches.end();
219 for (; Begin != End && Begin->getEnd() < ExpandedEndLoc; ++Begin)
220 if (Begin->getBegin() < ExpandedStartLoc)
238 const auto *If = Result.Nodes.getNodeAs<IfStmt>(
"if");
239 const auto *Else = Result.Nodes.getNodeAs<Stmt>(
"else");
240 const auto *OuterScope = Result.Nodes.getNodeAs<CompoundStmt>(
"cs");
242 SourceLocation ElseLoc = If->getElseLoc();
245 PPConditionals, *Result.SourceManager, Interrupt->getBeginLoc(),
249 bool IsLastInScope = OuterScope->body_back() == If;
253 if (WarnOnUnfixable) {
261 if (!WarnOnConditionVariables)
267 << ControlFlowInterrupter
268 << SourceRange(ElseLoc);
270 Diag << tooling::fixit::createReplacement(
271 SourceRange(If->getIfLoc()),
272 (tooling::fixit::getText(*If->getInit(), *Result.Context) +
273 llvm::StringRef(
"\n"))
275 << tooling::fixit::createRemoval(If->getInit()->getSourceRange());
277 const DeclStmt *VDeclStmt = If->getConditionVariableDeclStmt();
278 const VarDecl *VDecl = If->getConditionVariable();
280 (tooling::fixit::getText(*VDeclStmt, *Result.Context) +
281 llvm::StringRef(
";\n") +
282 tooling::fixit::getText(If->getIfLoc(), *Result.Context))
284 Diag << tooling::fixit::createReplacement(SourceRange(If->getIfLoc()),
286 << tooling::fixit::createReplacement(VDeclStmt->getSourceRange(),
289 }
else if (WarnOnUnfixable) {
297 if (!WarnOnConditionVariables)
303 << ControlFlowInterrupter
304 << SourceRange(ElseLoc);
305 Diag << tooling::fixit::createReplacement(
306 SourceRange(If->getIfLoc()),
307 (tooling::fixit::getText(*If->getInit(), *Result.Context) +
309 tooling::fixit::getText(If->getIfLoc(), *Result.Context))
311 << tooling::fixit::createRemoval(If->getInit()->getSourceRange());
313 }
else if (WarnOnUnfixable) {
321 << ControlFlowInterrupter << SourceRange(ElseLoc);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.