clang-tools 22.0.0git
InconsistentIfElseBracesCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/Stmt.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Lex/Lexer.h"
16
17using namespace clang::ast_matchers;
18
20
21/// Check that at least one branch of the \p If statement is a \c CompoundStmt.
22static bool shouldHaveBraces(const IfStmt *If) {
23 const Stmt *const Then = If->getThen();
24 if (isa<CompoundStmt>(Then))
25 return true;
26
27 if (const Stmt *const Else = If->getElse()) {
28 if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
29 return shouldHaveBraces(NestedIf);
30
31 return isa<CompoundStmt>(Else);
32 }
33
34 return false;
35}
36
38 Finder->addMatcher(
39 ifStmt(hasElse(anything()),
40 unless(isConsteval()), // 'if consteval' always has braces
41 unless(hasParent(ifStmt())))
42 .bind("if_stmt"),
43 this);
44}
45
47 const MatchFinder::MatchResult &Result) {
48 const auto *MatchedIf = Result.Nodes.getNodeAs<IfStmt>("if_stmt");
49 if (!shouldHaveBraces(MatchedIf))
50 return;
51 checkIfStmt(Result, MatchedIf);
52}
53
54void InconsistentIfElseBracesCheck::checkIfStmt(
55 const MatchFinder::MatchResult &Result, const IfStmt *If) {
56 const Stmt *Then = If->getThen();
57 if (const auto *NestedIf = dyn_cast<const IfStmt>(Then)) {
58 // If the then-branch is a nested IfStmt, first we need to add braces to
59 // it, then we need to check the inner IfStmt.
60 emitDiagnostic(Result, If->getThen(), If->getRParenLoc(), If->getElseLoc());
61
62 if (shouldHaveBraces(NestedIf))
63 checkIfStmt(Result, NestedIf);
64 } else if (!isa<CompoundStmt>(Then)) {
65 emitDiagnostic(Result, Then, If->getRParenLoc(), If->getElseLoc());
66 }
67
68 if (const Stmt *const Else = If->getElse()) {
69 if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
70 checkIfStmt(Result, NestedIf);
71 else if (!isa<CompoundStmt>(Else))
72 emitDiagnostic(Result, If->getElse(), If->getElseLoc());
73 }
74}
75
76void InconsistentIfElseBracesCheck::emitDiagnostic(
77 const MatchFinder::MatchResult &Result, const Stmt *S,
78 SourceLocation StartLoc, SourceLocation EndLocHint) {
79 if (StartLoc.isMacroID()) {
80 diag(StartLoc, "statement should have braces");
81 return;
82 }
83 const utils::BraceInsertionHints Hints = utils::getBraceInsertionsHints(
84 S, Result.Context->getLangOpts(), *Result.SourceManager, StartLoc,
85 EndLocHint);
86 assert(Hints && Hints.offersFixIts() && "Expected hints or fix-its");
87 diag(Hints.DiagnosticPos, "statement should have braces")
88 << Hints.openingBraceFixIt() << Hints.closingBraceFixIt();
89}
90
91} // namespace clang::tidy::readability
This file provides utilities to put braces around a statement.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static bool shouldHaveBraces(const IfStmt *If)
Check that at least one branch of the If statement is a CompoundStmt.
BraceInsertionHints getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts, const SourceManager &SM, SourceLocation StartLoc, SourceLocation EndLocHint)
Create fix-it hints for braces that wrap the given statement when applied.