clang-tools  7.0.0
MisleadingIndentationCheck.cpp
Go to the documentation of this file.
1 //===--- MisleadingIndentationCheck.cpp - clang-tidy-----------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace readability {
19 
20 static const IfStmt *getPrecedingIf(const SourceManager &SM,
21  ASTContext *Context, const IfStmt *If) {
22  auto parents = Context->getParents(*If);
23  if (parents.size() != 1)
24  return nullptr;
25  if (const auto *PrecedingIf = parents[0].get<IfStmt>()) {
26  SourceLocation PreviousElseLoc = PrecedingIf->getElseLoc();
27  if (SM.getExpansionLineNumber(PreviousElseLoc) ==
28  SM.getExpansionLineNumber(If->getIfLoc()))
29  return PrecedingIf;
30  }
31  return nullptr;
32 }
33 
34 void MisleadingIndentationCheck::danglingElseCheck(const SourceManager &SM,
35  ASTContext *Context,
36  const IfStmt *If) {
37  SourceLocation IfLoc = If->getIfLoc();
38  SourceLocation ElseLoc = If->getElseLoc();
39 
40  if (IfLoc.isMacroID() || ElseLoc.isMacroID())
41  return;
42 
43  if (SM.getExpansionLineNumber(If->getThen()->getLocEnd()) ==
44  SM.getExpansionLineNumber(ElseLoc))
45  return;
46 
47  // Find location of first 'if' in a 'if else if' chain.
48  for (auto PrecedingIf = getPrecedingIf(SM, Context, If); PrecedingIf;
49  PrecedingIf = getPrecedingIf(SM, Context, PrecedingIf))
50  IfLoc = PrecedingIf->getIfLoc();
51 
52  if (SM.getExpansionColumnNumber(IfLoc) !=
53  SM.getExpansionColumnNumber(ElseLoc))
54  diag(ElseLoc, "different indentation for 'if' and corresponding 'else'");
55 }
56 
57 void MisleadingIndentationCheck::missingBracesCheck(const SourceManager &SM,
58  const CompoundStmt *CStmt) {
59  const static StringRef StmtNames[] = {"if", "for", "while"};
60  for (unsigned int i = 0; i < CStmt->size() - 1; i++) {
61  const Stmt *CurrentStmt = CStmt->body_begin()[i];
62  const Stmt *Inner = nullptr;
63  int StmtKind = 0;
64 
65  if (const auto *CurrentIf = dyn_cast<IfStmt>(CurrentStmt)) {
66  StmtKind = 0;
67  Inner =
68  CurrentIf->getElse() ? CurrentIf->getElse() : CurrentIf->getThen();
69  } else if (const auto *CurrentFor = dyn_cast<ForStmt>(CurrentStmt)) {
70  StmtKind = 1;
71  Inner = CurrentFor->getBody();
72  } else if (const auto *CurrentWhile = dyn_cast<WhileStmt>(CurrentStmt)) {
73  StmtKind = 2;
74  Inner = CurrentWhile->getBody();
75  } else {
76  continue;
77  }
78 
79  if (isa<CompoundStmt>(Inner))
80  continue;
81 
82  SourceLocation InnerLoc = Inner->getLocStart();
83  SourceLocation OuterLoc = CurrentStmt->getLocStart();
84 
85  if (SM.getExpansionLineNumber(InnerLoc) ==
86  SM.getExpansionLineNumber(OuterLoc))
87  continue;
88 
89  const Stmt *NextStmt = CStmt->body_begin()[i + 1];
90  SourceLocation NextLoc = NextStmt->getLocStart();
91 
92  if (InnerLoc.isMacroID() || OuterLoc.isMacroID() || NextLoc.isMacroID())
93  continue;
94 
95  if (SM.getExpansionColumnNumber(InnerLoc) ==
96  SM.getExpansionColumnNumber(NextLoc)) {
97  diag(NextLoc, "misleading indentation: statement is indented too deeply");
98  diag(OuterLoc, "did you mean this line to be inside this '%0'",
99  DiagnosticIDs::Note)
100  << StmtNames[StmtKind];
101  }
102  }
103 }
104 
105 void MisleadingIndentationCheck::registerMatchers(MatchFinder *Finder) {
106  Finder->addMatcher(ifStmt(hasElse(stmt())).bind("if"), this);
107  Finder->addMatcher(
108  compoundStmt(has(stmt(anyOf(ifStmt(), forStmt(), whileStmt()))))
109  .bind("compound"),
110  this);
111 }
112 
113 void MisleadingIndentationCheck::check(const MatchFinder::MatchResult &Result) {
114  if (const auto *If = Result.Nodes.getNodeAs<IfStmt>("if"))
115  danglingElseCheck(*Result.SourceManager, Result.Context, If);
116 
117  if (const auto *CStmt = Result.Nodes.getNodeAs<CompoundStmt>("compound"))
118  missingBracesCheck(*Result.SourceManager, CStmt);
119 }
120 
121 } // namespace readability
122 } // namespace tidy
123 } // namespace clang
static const IfStmt * getPrecedingIf(const SourceManager &SM, ASTContext *Context, const IfStmt *If)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//