[clang-tools-extra] r218898 - [clang-tidy] Add check misc-braces-around-statements.

Alexander Kornienko alexfh at google.com
Thu Oct 2 12:09:57 PDT 2014


Author: alexfh
Date: Thu Oct  2 14:09:56 2014
New Revision: 218898

URL: http://llvm.org/viewvc/llvm-project?rev=218898&view=rev
Log:
[clang-tidy] Add check misc-braces-around-statements.

This check looks for if statements and loops: for, range-for, while and
do-while, and verifies that the inside statements are inside braces '{}'.
If not, proposes to add braces around them.

Example:

  if (condition)
    action();

becomes

  if (condition) {
    action();
  }

This check ought to be used with the -format option, so that the braces be
well-formatted.


Patch by Marek Kurdej!

http://reviews.llvm.org/D5395


Added:
    clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.cpp
    clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.h
    clang-tools-extra/trunk/test/clang-tidy/misc-braces-around-statements.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
    clang-tools-extra/trunk/unittests/clang-tidy/MiscModuleTest.cpp

Added: clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.cpp?rev=218898&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.cpp Thu Oct  2 14:09:56 2014
@@ -0,0 +1,239 @@
+//===--- BracesAroundStatementsCheck.cpp - clang-tidy ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BracesAroundStatementsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace {
+
+tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
+                            const ASTContext *Context) {
+  Token Tok;
+  SourceLocation Beginning =
+      Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts());
+  const bool Invalid =
+      Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts());
+  assert(!Invalid && "Expected a valid token.");
+
+  if (Invalid)
+    return tok::NUM_TOKENS;
+
+  return Tok.getKind();
+}
+
+SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc,
+                                                const SourceManager &SM,
+                                                const ASTContext *Context) {
+  assert(Loc.isValid());
+  for (;;) {
+    while (isWhitespace(*FullSourceLoc(Loc, SM).getCharacterData()))
+      Loc = Loc.getLocWithOffset(1);
+
+    tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+    if (TokKind == tok::NUM_TOKENS || TokKind != tok::comment)
+      return Loc;
+
+    // Fast-forward current token.
+    Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+  }
+}
+
+SourceLocation findEndLocation(SourceLocation LastTokenLoc,
+                               const SourceManager &SM,
+                               const ASTContext *Context) {
+  SourceLocation Loc = LastTokenLoc;
+  // Loc points to the beginning of the last (non-comment non-ws) token
+  // before end or ';'.
+  assert(Loc.isValid());
+  bool SkipEndWhitespaceAndComments = true;
+  tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+  if (TokKind == tok::NUM_TOKENS || TokKind == tok::semi ||
+      TokKind == tok::r_brace) {
+    // If we are at ";" or "}", we found the last token. We could use as well
+    // `if (isa<NullStmt>(S))`, but it wouldn't work for nested statements.
+    SkipEndWhitespaceAndComments = false;
+  }
+
+  Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+  // Loc points past the last token before end or after ';'.
+
+  if (SkipEndWhitespaceAndComments) {
+    Loc = forwardSkipWhitespaceAndComments(Loc, SM, Context);
+    tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+    if (TokKind == tok::semi)
+      Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+  }
+
+  for (;;) {
+    assert(Loc.isValid());
+    while (isHorizontalWhitespace(*FullSourceLoc(Loc, SM).getCharacterData()))
+      Loc = Loc.getLocWithOffset(1);
+
+    if (isVerticalWhitespace(*FullSourceLoc(Loc, SM).getCharacterData())) {
+      // EOL, insert brace before.
+      break;
+    }
+    tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+    if (TokKind != tok::comment) {
+      // Non-comment token, insert brace before.
+      break;
+    }
+
+    SourceLocation TokEndLoc =
+        Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+    SourceRange TokRange(Loc, TokEndLoc);
+    StringRef Comment = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts());
+    if (Comment.startswith("/*") && Comment.find('\n') != StringRef::npos) {
+      // Multi-line block comment, insert brace before.
+      break;
+    }
+    // else: Trailing comment, insert brace after the newline.
+
+    // Fast-forward current token.
+    Loc = TokEndLoc;
+  }
+  return Loc;
+}
+
+} // namespace
+
+void BracesAroundStatementsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(ifStmt().bind("if"), this);
+  Finder->addMatcher(whileStmt().bind("while"), this);
+  Finder->addMatcher(doStmt().bind("do"), this);
+  Finder->addMatcher(forStmt().bind("for"), this);
+  Finder->addMatcher(forRangeStmt().bind("for-range"), this);
+}
+
+void
+BracesAroundStatementsCheck::check(const MatchFinder::MatchResult &Result) {
+  const SourceManager &SM = *Result.SourceManager;
+  const ASTContext *Context = Result.Context;
+
+  // Get location of closing parenthesis or 'do' to insert opening brace.
+  if (auto S = Result.Nodes.getNodeAs<ForStmt>("for")) {
+    checkStmt(Result, S->getBody(), S->getRParenLoc());
+  } else if (auto S = Result.Nodes.getNodeAs<CXXForRangeStmt>("for-range")) {
+    checkStmt(Result, S->getBody(), S->getRParenLoc());
+  } else if (auto S = Result.Nodes.getNodeAs<DoStmt>("do")) {
+    checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc());
+  } else if (auto S = Result.Nodes.getNodeAs<WhileStmt>("while")) {
+    SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+    if (StartLoc.isInvalid())
+      return;
+    checkStmt(Result, S->getBody(), StartLoc);
+  } else if (auto S = Result.Nodes.getNodeAs<IfStmt>("if")) {
+    SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+    if (StartLoc.isInvalid())
+      return;
+    checkStmt(Result, S->getThen(), StartLoc, S->getElseLoc());
+    const Stmt *Else = S->getElse();
+    if (Else && !isa<IfStmt>(Else)) {
+      // Omit 'else if' statements here, they will be handled directly.
+      checkStmt(Result, Else, S->getElseLoc());
+    }
+  } else {
+    llvm_unreachable("Invalid match");
+  }
+}
+
+/// Find location of right parenthesis closing condition
+template <typename IfOrWhileStmt>
+SourceLocation
+BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
+                                           const SourceManager &SM,
+                                           const ASTContext *Context) {
+  // Skip macros
+  if (S->getLocStart().isMacroID())
+    return SourceLocation();
+
+  static const char *const ErrorMessage =
+      "cannot find location of closing parenthesis ')'";
+  SourceLocation CondEndLoc = S->getCond()->getLocEnd();
+  if (const DeclStmt *CondVar = S->getConditionVariableDeclStmt())
+    CondEndLoc = CondVar->getLocEnd();
+
+  assert(CondEndLoc.isValid());
+  SourceLocation PastCondEndLoc =
+      Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts());
+  if (PastCondEndLoc.isInvalid()) {
+    diag(CondEndLoc, ErrorMessage);
+    return SourceLocation();
+  }
+  SourceLocation RParenLoc =
+      forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context);
+  if (RParenLoc.isInvalid()) {
+    diag(PastCondEndLoc, ErrorMessage);
+    return SourceLocation();
+  }
+  tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context);
+  if (TokKind != tok::r_paren) {
+    diag(RParenLoc, ErrorMessage);
+    return SourceLocation();
+  }
+  return RParenLoc;
+}
+
+void
+BracesAroundStatementsCheck::checkStmt(const MatchFinder::MatchResult &Result,
+                                       const Stmt *S, SourceLocation InitialLoc,
+                                       SourceLocation EndLocHint) {
+  // 1) If there's a corresponding "else" or "while", the check inserts "} "
+  // right before that token.
+  // 2) If there's a multi-line block comment starting on the same line after
+  // the location we're inserting the closing brace at, or there's a non-comment
+  // token, the check inserts "\n}" right before that token.
+  // 3) Otherwise the check finds the end of line (possibly after some block or
+  // line comments) and inserts "\n}" right before that EOL.
+  if (!S || isa<CompoundStmt>(S)) {
+    // Already inside braces.
+    return;
+  }
+  // Skip macros.
+  if (S->getLocStart().isMacroID())
+    return;
+
+  // TODO: Add an option to insert braces if:
+  //   * the body doesn't fit on the same line with the control statement
+  //   * the body takes more than one line
+  //   * always.
+
+  const SourceManager &SM = *Result.SourceManager;
+  const ASTContext *Context = Result.Context;
+
+  // InitialLoc points at the last token before opening brace to be inserted.
+  assert(InitialLoc.isValid());
+  SourceLocation StartLoc =
+      Lexer::getLocForEndOfToken(InitialLoc, 0, SM, Context->getLangOpts());
+  // StartLoc points at the location of the opening brace to be inserted.
+  SourceLocation EndLoc;
+  std::string ClosingInsertion;
+  if (EndLocHint.isValid()) {
+    EndLoc = EndLocHint;
+    ClosingInsertion = "} ";
+  } else {
+    EndLoc = findEndLocation(S->getLocEnd(), SM, Context);
+    ClosingInsertion = "\n}";
+  }
+
+  assert(StartLoc.isValid());
+  auto Diag = diag(StartLoc, "statement should be inside braces");
+  Diag << FixItHint::CreateInsertion(StartLoc, " {")
+       << FixItHint::CreateInsertion(EndLoc, ClosingInsertion);
+}
+
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.h?rev=218898&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/BracesAroundStatementsCheck.h Thu Oct  2 14:09:56 2014
@@ -0,0 +1,37 @@
+//===--- BracesAroundStatementsCheck.h - clang-tidy -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BRACES_AROUND_STATEMENTS_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BRACES_AROUND_STATEMENTS_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+class BracesAroundStatementsCheck : public ClangTidyCheck {
+public:
+  BracesAroundStatementsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  void checkStmt(const ast_matchers::MatchFinder::MatchResult &Result,
+                 const Stmt *S, SourceLocation StartLoc,
+                 SourceLocation EndLocHint = SourceLocation());
+  template <typename IfOrWhileStmt>
+  SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM,
+                               const ASTContext *Context);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BRACES_AROUND_STATEMENTS_CHECK_H

Modified: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt?rev=218898&r1=218897&r2=218898&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt Thu Oct  2 14:09:56 2014
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
 add_clang_library(clangTidyMiscModule
   ArgumentCommentCheck.cpp
   BoolPointerImplicitConversion.cpp
+  BracesAroundStatementsCheck.cpp
   FunctionSize.cpp
   MiscTidyModule.cpp
   RedundantSmartptrGet.cpp

Modified: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp?rev=218898&r1=218897&r2=218898&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp Thu Oct  2 14:09:56 2014
@@ -12,6 +12,7 @@
 #include "../ClangTidyModuleRegistry.h"
 #include "ArgumentCommentCheck.h"
 #include "BoolPointerImplicitConversion.h"
+#include "BracesAroundStatementsCheck.h"
 #include "FunctionSize.h"
 #include "RedundantSmartptrGet.h"
 #include "SwappedArgumentsCheck.h"
@@ -28,6 +29,8 @@ public:
     CheckFactories.registerCheck<ArgumentCommentCheck>("misc-argument-comment");
     CheckFactories.registerCheck<BoolPointerImplicitConversion>(
         "misc-bool-pointer-implicit-conversion");
+    CheckFactories.registerCheck<BracesAroundStatementsCheck>(
+        "misc-braces-around-statements");
     CheckFactories.registerCheck<FunctionSizeCheck>("misc-function-size");
     CheckFactories.registerCheck<RedundantSmartptrGet>(
         "misc-redundant-smartptr-get");

Added: clang-tools-extra/trunk/test/clang-tidy/misc-braces-around-statements.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-braces-around-statements.cpp?rev=218898&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-braces-around-statements.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-braces-around-statements.cpp Thu Oct  2 14:09:56 2014
@@ -0,0 +1,178 @@
+// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s misc-braces-around-statements %t
+// REQUIRES: shell
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+  return false;
+}
+
+#define EMPTY_MACRO
+#define EMPTY_MACRO_FUN()
+
+void test() {
+  // CHECK-NOT: warning
+  // if
+  if (cond("if1") /*comment*/)
+    // some comment
+    do_something("if1");
+  // CHECK-MESSAGES: :[[@LINE-3]]:31: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("if1") /*comment*/) {
+  // CHECK-FIXES: }
+  if (cond("if2")) {
+    do_something("if2");
+  }
+  if (cond("if3"))
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("if3")) {
+  // CHECK-FIXES: }
+
+  // if-else
+  if (cond("if-else1"))
+    do_something("if-else1");
+  // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("if-else1")) {
+  // CHECK-FIXES: } else {
+  else
+    do_something("if-else1 else");
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
+  // CHECK-FIXES: }
+  if (cond("if-else2")) {
+    do_something("if-else2");
+  } else {
+    do_something("if-else2 else");
+  }
+
+  // CHECK-NOT: warning
+  // if-else if-else
+  if (cond("if-else if-else1"))
+    do_something("if");
+  // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: statement should be inside braces
+  // CHECK-FIXES: } else if (cond("else if1")) {
+  else if (cond("else if1"))
+    do_something("else if");
+  // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: statement should be inside braces
+  else
+    do_something("else");
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
+  // CHECK-FIXES: }
+  if (cond("if-else if-else2")) {
+    do_something("if");
+  } else if (cond("else if2")) {
+    do_something("else if");
+  } else {
+    do_something("else");
+  }
+
+  // CHECK-NOT: warning
+  for (;;)
+    do_something("for");
+  // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
+  // CHECK-FIXES: for (;;) {
+  // CHECK-FIXES: }
+  for (;;) {
+    do_something("for");
+  }
+  for (;;)
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
+  // CHECK-FIXES: for (;;) {
+  // CHECK-FIXES: }
+
+  // CHECK-NOT: warning
+  int arr[4] = {1, 2, 3, 4};
+  for (int a : arr)
+    do_something("for-range");
+  // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: statement should be inside braces
+  // CHECK-FIXES: for (int a : arr) {
+  // CHECK-FIXES: }
+  for (int a : arr) {
+    do_something("for-range");
+  }
+  for (int a : arr)
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: statement should be inside braces
+  // CHECK-FIXES: for (int a : arr) {
+  // CHECK-FIXES: }
+
+  // CHECK-NOT: warning
+  while (cond("while1"))
+    do_something("while");
+  // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: statement should be inside braces
+  // CHECK-FIXES: while (cond("while1")) {
+  // CHECK-FIXES: }
+  while (cond("while2")) {
+    do_something("while");
+  }
+  while (false)
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: statement should be inside braces
+  // CHECK-FIXES: while (false) {
+  // CHECK-FIXES: }
+
+  // CHECK-NOT: warning
+  do
+    do_something("do1");
+  while (cond("do1"));
+  // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
+  // CHECK-FIXES: do {
+  // CHECK-FIXES: } while (cond("do1"));
+  do {
+    do_something("do2");
+  } while (cond("do2"));
+
+  do
+    ;
+  while (false);
+  // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
+  // CHECK-FIXES: do {
+  // CHECK-FIXES: } while (false);
+
+  // CHECK-NOT: warning
+  if (cond("ifif1"))
+    // comment
+    if (cond("ifif2"))
+      // comment
+      /*comment*/ ; // comment
+  // CHECK-MESSAGES: :[[@LINE-5]]:21: warning: statement should be inside braces
+  // CHECK-MESSAGES: :[[@LINE-4]]:23: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("ifif1")) {
+  // CHECK-FIXES: if (cond("ifif2")) {
+  // CHECK-FIXES: }
+  // CHECK-FIXES-NEXT: }
+
+  if (cond("ifif3"))
+    // comment
+    if (cond("ifif4")) {
+      // comment
+      /*comment*/; // comment
+    }
+  // CHECK-MESSAGES: :[[@LINE-6]]:21: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("ifif3")) {
+  // CHECK-FIXES: }
+
+  if (cond("ifif5"))
+    ; /* multi-line
+        comment */
+  // CHECK-MESSAGES: :[[@LINE-3]]:21: warning: statement should be inside braces
+  // CHECK-FIXES: if (cond("ifif5")) {
+  // CHECK-FIXES: }/* multi-line
+
+  // CHECK-NOT: warning
+  if (1) while (2) if (3) for (;;) do ; while(false) /**/;/**/
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: statement should be inside braces
+  // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+  // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: statement should be inside braces
+  // CHECK-MESSAGES: :[[@LINE-4]]:35: warning: statement should be inside braces
+  // CHECK-MESSAGES: :[[@LINE-5]]:38: warning: statement should be inside braces
+  // CHECK-FIXES: if (1) { while (2) { if (3) { for (;;) { do { ; } while(false) /**/;/**/
+  // CHECK-FIXES-NEXT: }
+  // CHECK-FIXES-NEXT: }
+  // CHECK-FIXES-NEXT: }
+  // CHECK-FIXES-NEXT: }
+
+  // CHECK-NOT: warning
+
+  // CHECK-MESSAGES: {{clang-tidy applied [0-9]+ of [0-9]+ suggested fixes.}}
+}

Modified: clang-tools-extra/trunk/unittests/clang-tidy/MiscModuleTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/MiscModuleTest.cpp?rev=218898&r1=218897&r2=218898&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/MiscModuleTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-tidy/MiscModuleTest.cpp Thu Oct  2 14:09:56 2014
@@ -1,5 +1,6 @@
 #include "ClangTidyTest.h"
 #include "misc/ArgumentCommentCheck.h"
+#include "misc/BracesAroundStatementsCheck.h"
 #include "gtest/gtest.h"
 
 namespace clang {
@@ -35,6 +36,334 @@ TEST(ArgumentCommentCheckTest, OtherEdit
                     "void f(int xxx, int yyy); void g() { f(/*xxy=*/0, 0); }");
 }
 
+TEST(BracesAroundStatementsCheck, IfWithComments) {
+  EXPECT_EQ("int main() {\n"
+            "  if (false /*dummy token*/) {\n"
+            "    // comment\n"
+            "    return -1; /**/\n"
+            "}\n"
+            "  if (false) {\n"
+            "    return -1; // comment\n"
+            "}\n"
+            "  if (false) {\n"
+            "    return -1; \n"
+            "}/* multi-line \n comment */\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  if (false /*dummy token*/)\n"
+                "    // comment\n"
+                "    return -1; /**/\n"
+                "  if (false)\n"
+                "    return -1; // comment\n"
+                "  if (false)\n"
+                "    return -1; /* multi-line \n comment */\n"
+                "}"));
+  EXPECT_EQ("int main() {\n"
+            "  if (false /*dummy token*/) {\n"
+            "    // comment\n"
+            "    return -1 /**/ ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  if (false /*dummy token*/)\n"
+                "    // comment\n"
+                "    return -1 /**/ ;\n"
+                "}"));
+}
+
+TEST(BracesAroundStatementsCheck, If) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  if (false) {\n"
+                                                 "    return -1;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  if (auto Cond = false) {\n"
+                                                 "    return -1;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  if (false) {\n"
+                                                 "    return -1;\n"
+                                                 "  } else {\n"
+                                                 "    return -2;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_EQ("int main() {\n"
+            "  if (false) {\n"
+            "    return -1;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  if (false)\n"
+                                                        "    return -1;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  if (auto Cond = false /**/ ) {\n"
+            "    return -1;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  if (auto Cond = false /**/ )\n"
+                "    return -1;\n"
+                "}"));
+  // FIXME: Consider adding braces before EMPTY_MACRO and after the statement.
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+                    "#define EMPTY_MACRO\n"
+                    "int main() {\n"
+                    "  if (auto Cond = false EMPTY_MACRO /**/ ) EMPTY_MACRO\n"
+                    "    return -1;\n"
+                    "}");
+  EXPECT_EQ("int main() {\n"
+            "  if (true) { return -1/**/ ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  if (true) return -1/**/ ;\n"
+                "}"));
+  EXPECT_EQ("int main() {\n"
+            "  if (false) {\n"
+            "    return -1;\n"
+            "  } else {\n"
+            "    return -2;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  if (false)\n"
+                                                        "    return -1;\n"
+                                                        "  else\n"
+                                                        "    return -2;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  if (false) {\n"
+            "    return -1;\n"
+            "  } else if (1 == 2) {\n"
+            "    return -2;\n"
+            "  } else {\n"
+            "    return -3;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  if (false)\n"
+                                                        "    return -1;\n"
+                                                        "  else if (1 == 2)\n"
+                                                        "    return -2;\n"
+                                                        "  else\n"
+                                                        "    return -3;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  if (false) {\n"
+            "    return -1;\n"
+            "  } else if (1 == 2) {\n"
+            "    return -2;\n"
+            "  } else {\n"
+            "    return -3;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  if (false)\n"
+                                                        "    return -1;\n"
+                                                        "  else if (1 == 2) {\n"
+                                                        "    return -2;\n"
+                                                        "  } else\n"
+                                                        "    return -3;\n"
+                                                        "}"));
+}
+
+TEST(BracesAroundStatementsCheck, For) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  for (;;) {\n"
+                                                 "    ;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_EQ("int main() {\n"
+            "  for (;;) {\n"
+            "    ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  for (;;)\n"
+                                                        "    ;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  for (;;) {\n"
+            "    /**/ ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  for (;;)\n"
+                                                        "    /**/ ;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  for (;;) {\n"
+            "    return -1 /**/ ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  for (;;)\n"
+                                                        "    return -1 /**/ ;\n"
+                                                        "}"));
+}
+
+TEST(BracesAroundStatementsCheck, ForRange) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  int arr[4];\n"
+                                                 "  for (int i : arr) {\n"
+                                                 "    ;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_EQ("int main() {\n"
+            "  int arr[4];\n"
+            "  for (int i : arr) {\n"
+            "    ;\n"
+            "}\n"
+            "  for (int i : arr) {\n"
+            "    return -1 ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  int arr[4];\n"
+                                                        "  for (int i : arr)\n"
+                                                        "    ;\n"
+                                                        "  for (int i : arr)\n"
+                                                        "    return -1 ;\n"
+                                                        "}"));
+}
+
+TEST(BracesAroundStatementsCheck, DoWhile) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  do {\n"
+                                                 "    ;\n"
+                                                 "  } while (false);\n"
+                                                 "}");
+  EXPECT_EQ("int main() {\n"
+            "  do {\n"
+            "    ;\n"
+            "  } while (false);\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  do\n"
+                                                        "    ;\n"
+                                                        "  while (false);\n"
+                                                        "}"));
+}
+
+TEST(BracesAroundStatementsCheck, While) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+                                                 "  while (false) {\n"
+                                                 "    ;\n"
+                                                 "  }\n"
+                                                 "}");
+  EXPECT_EQ("int main() {\n"
+            "  while (false) {\n"
+            "    ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  while (false)\n"
+                                                        "    ;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  while (auto Cond = false) {\n"
+            "    ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  while (auto Cond = false)\n"
+                "    ;\n"
+                "}"));
+  EXPECT_EQ("int main() {\n"
+            "  while (false /*dummy token*/) {\n"
+            "    ;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  while (false /*dummy token*/)\n"
+                "    ;\n"
+                "}"));
+  EXPECT_EQ("int main() {\n"
+            "  while (false) {\n"
+            "    break;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  while (false)\n"
+                                                        "    break;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  while (false) {\n"
+            "    break /**/;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  while (false)\n"
+                                                        "    break /**/;\n"
+                                                        "}"));
+  EXPECT_EQ("int main() {\n"
+            "  while (false) {\n"
+            "    /**/;\n"
+            "}\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                        "  while (false)\n"
+                                                        "    /**/;\n"
+                                                        "}"));
+}
+
+TEST(BracesAroundStatementsCheck, Nested) {
+  EXPECT_EQ("int main() {\n"
+            "  do { if (true) {}} while (false);\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  do if (true) {}while (false);\n"
+                "}"));
+  EXPECT_EQ("int main() {\n"
+            "  do { if (true) {}} while (false);\n"
+            "}",
+            runCheckOnCode<BracesAroundStatementsCheck>(
+                "int main() {\n"
+                "  do if (true) {}while (false);\n"
+                "}"));
+  EXPECT_EQ(
+      "int main() {\n"
+      "  if (true) {\n"
+      "    // comment\n"
+      "    if (false) {\n"
+      "      // comment\n"
+      "      /**/ ; // comment\n"
+      "    }\n"
+      "}\n"
+      "}",
+      runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+                                                  "  if (true)\n"
+                                                  "    // comment\n"
+                                                  "    if (false) {\n"
+                                                  "      // comment\n"
+                                                  "      /**/ ; // comment\n"
+                                                  "    }\n"
+                                                  "}"));
+}
+
+TEST(BracesAroundStatementsCheck, Macros) {
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+                    "#define IF(COND) if (COND) return -1;\n"
+                    "int main() {\n"
+                    "  IF(false)\n"
+                    "}");
+  EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+                    "#define FOR(COND) for (COND) return -1;\n"
+                    "int main() {\n"
+                    "  FOR(;;)\n"
+                    "}");
+}
+
 } // namespace test
 } // namespace tidy
 } // namespace clang





More information about the cfe-commits mailing list