[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang-tools-extra / clang-tidy / readability / MisleadingIndentationCheck.cpp
blob2c011f5c0e690485eee5fda1a521b996396be01c
1 //===--- MisleadingIndentationCheck.cpp - clang-tidy-----------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "MisleadingIndentationCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers;
15 namespace clang::tidy::readability {
17 static const IfStmt *getPrecedingIf(const SourceManager &SM,
18 ASTContext *Context, const IfStmt *If) {
19 auto Parents = Context->getParents(*If);
20 if (Parents.size() != 1)
21 return nullptr;
22 if (const auto *PrecedingIf = Parents[0].get<IfStmt>()) {
23 SourceLocation PreviousElseLoc = PrecedingIf->getElseLoc();
24 if (SM.getExpansionLineNumber(PreviousElseLoc) ==
25 SM.getExpansionLineNumber(If->getIfLoc()))
26 return PrecedingIf;
28 return nullptr;
31 void MisleadingIndentationCheck::danglingElseCheck(const SourceManager &SM,
32 ASTContext *Context,
33 const IfStmt *If) {
34 SourceLocation IfLoc = If->getIfLoc();
35 SourceLocation ElseLoc = If->getElseLoc();
37 if (IfLoc.isMacroID() || ElseLoc.isMacroID())
38 return;
40 if (SM.getExpansionLineNumber(If->getThen()->getEndLoc()) ==
41 SM.getExpansionLineNumber(ElseLoc))
42 return;
44 // Find location of first 'if' in a 'if else if' chain.
45 for (const auto *PrecedingIf = getPrecedingIf(SM, Context, If); PrecedingIf;
46 PrecedingIf = getPrecedingIf(SM, Context, PrecedingIf))
47 IfLoc = PrecedingIf->getIfLoc();
49 if (SM.getExpansionColumnNumber(IfLoc) !=
50 SM.getExpansionColumnNumber(ElseLoc))
51 diag(ElseLoc, "different indentation for 'if' and corresponding 'else'");
54 void MisleadingIndentationCheck::missingBracesCheck(const SourceManager &SM,
55 const CompoundStmt *CStmt) {
56 const static StringRef StmtNames[] = {"if", "for", "while"};
57 for (unsigned int I = 0; I < CStmt->size() - 1; I++) {
58 const Stmt *CurrentStmt = CStmt->body_begin()[I];
59 const Stmt *Inner = nullptr;
60 int StmtKind = 0;
62 if (const auto *CurrentIf = dyn_cast<IfStmt>(CurrentStmt)) {
63 StmtKind = 0;
64 Inner =
65 CurrentIf->getElse() ? CurrentIf->getElse() : CurrentIf->getThen();
66 } else if (const auto *CurrentFor = dyn_cast<ForStmt>(CurrentStmt)) {
67 StmtKind = 1;
68 Inner = CurrentFor->getBody();
69 } else if (const auto *CurrentWhile = dyn_cast<WhileStmt>(CurrentStmt)) {
70 StmtKind = 2;
71 Inner = CurrentWhile->getBody();
72 } else {
73 continue;
76 if (isa<CompoundStmt>(Inner))
77 continue;
79 SourceLocation InnerLoc = Inner->getBeginLoc();
80 SourceLocation OuterLoc = CurrentStmt->getBeginLoc();
82 if (InnerLoc.isInvalid() || InnerLoc.isMacroID() || OuterLoc.isInvalid() ||
83 OuterLoc.isMacroID())
84 continue;
86 if (SM.getExpansionLineNumber(InnerLoc) ==
87 SM.getExpansionLineNumber(OuterLoc))
88 continue;
90 const Stmt *NextStmt = CStmt->body_begin()[I + 1];
91 SourceLocation NextLoc = NextStmt->getBeginLoc();
93 if (NextLoc.isInvalid() || NextLoc.isMacroID())
94 continue;
96 if (SM.getExpansionColumnNumber(InnerLoc) ==
97 SM.getExpansionColumnNumber(NextLoc)) {
98 diag(NextLoc, "misleading indentation: statement is indented too deeply");
99 diag(OuterLoc, "did you mean this line to be inside this '%0'",
100 DiagnosticIDs::Note)
101 << StmtNames[StmtKind];
106 void MisleadingIndentationCheck::registerMatchers(MatchFinder *Finder) {
107 Finder->addMatcher(
108 ifStmt(unless(hasThen(nullStmt())), hasElse(stmt())).bind("if"), this);
109 Finder->addMatcher(
110 compoundStmt(has(stmt(anyOf(ifStmt(), forStmt(), whileStmt()))))
111 .bind("compound"),
112 this);
115 void MisleadingIndentationCheck::check(const MatchFinder::MatchResult &Result) {
116 if (const auto *If = Result.Nodes.getNodeAs<IfStmt>("if"))
117 danglingElseCheck(*Result.SourceManager, Result.Context, If);
119 if (const auto *CStmt = Result.Nodes.getNodeAs<CompoundStmt>("compound"))
120 missingBracesCheck(*Result.SourceManager, CStmt);
123 } // namespace clang::tidy::readability