diff options
6 files changed, 787 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.cpp new file mode 100644 index 00000000000..b3953a95a6a --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.cpp @@ -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 diff --git a/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.h b/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.h new file mode 100644 index 00000000000..95e522b3677 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/BracesAroundStatementsCheck.h @@ -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 diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 33bac3f2def..8442530eea5 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -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 diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 6cfc967fbed..c24897d9ffb 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -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"); diff --git a/clang-tools-extra/test/clang-tidy/misc-braces-around-statements.cpp b/clang-tools-extra/test/clang-tidy/misc-braces-around-statements.cpp new file mode 100644 index 00000000000..44de6a03d47 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/misc-braces-around-statements.cpp @@ -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.}} +} diff --git a/clang-tools-extra/unittests/clang-tidy/MiscModuleTest.cpp b/clang-tools-extra/unittests/clang-tidy/MiscModuleTest.cpp index 3f8222e297d..97390c267dd 100644 --- a/clang-tools-extra/unittests/clang-tidy/MiscModuleTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/MiscModuleTest.cpp @@ -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, OtherEditDistanceBelowThreshold) { "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 |