Index: clang-tidy/misc/BracesAroundStatementsCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/BracesAroundStatementsCheck.h @@ -0,0 +1,33 @@ +//===--- 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, int Offset = 0); +}; + +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BRACES_AROUND_STATEMENTS_CHECK_H Index: clang-tidy/misc/BracesAroundStatementsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/BracesAroundStatementsCheck.cpp @@ -0,0 +1,80 @@ +//===--- 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 { + +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 ast_matchers::MatchFinder::MatchResult &Result) { + const ForStmt *FS = Result.Nodes.getNodeAs("for"); + if (FS) { + checkStmt(Result, FS->getBody()); + } + const CXXForRangeStmt *FRS = Result.Nodes.getNodeAs("for-range"); + if (FRS) { + checkStmt(Result, FRS->getBody()); + } + const DoStmt *DS = Result.Nodes.getNodeAs("do"); + if (DS) { + checkStmt(Result, DS->getBody()); + } + const WhileStmt *WS = Result.Nodes.getNodeAs("while"); + if (WS) { + checkStmt(Result, WS->getBody()); + } + const IfStmt *IS = Result.Nodes.getNodeAs("if"); + if (IS) { + // NOTE: IfStmt's need additional offset, because SourceRange ends before + // semicolon ';' + checkStmt(Result, IS->getThen(), 1); + const Stmt* Else = IS->getElse(); + if (Else && !IfStmt::classof(Else)) { + // omit else if statements here, they will be handled directly + checkStmt(Result, Else, 1); + } + } +} + +void BracesAroundStatementsCheck::checkStmt( + const ast_matchers::MatchFinder::MatchResult &Result, + const Stmt *S, int Offset) { + if (!S) { + return; + } + if (!CompoundStmt::classof(S)) { + //SourceLocation EndLoc = Lexer::getLocForEndOfToken(S->getLocEnd(), 0, + // *Result.SourceManager, Result.Context->getLangOpts()); + //SourceLocation EndLoc = S->getLocEnd(); + //SourceLocation EndLoc = S->getLocEnd().getLocWithOffset(1 + Offset); // passes unittests + SourceLocation EndLoc = S->getLocEnd().getLocWithOffset(2); // passes tests + auto Diag = diag(S->getLocStart(), "statement should be inside braces"); + // add braces + Diag << FixItHint::CreateInsertion(S->getLocStart(), "{") + << FixItHint::CreateInsertion(EndLoc, "}"); + } +} + +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp BoolPointerImplicitConversion.cpp + BracesAroundStatementsCheck.cpp FunctionSize.cpp MiscTidyModule.cpp RedundantSmartptrGet.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ 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 @@ CheckFactories.registerCheck("misc-argument-comment"); CheckFactories.registerCheck( "misc-bool-pointer-implicit-conversion"); + CheckFactories.registerCheck( + "misc-braces-around-statements"); CheckFactories.registerCheck("misc-function-size"); CheckFactories.registerCheck( "misc-redundant-smartptr-get"); Index: test/clang-tidy/misc-braces-around-statements.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-braces-around-statements.cpp @@ -0,0 +1,57 @@ +// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s misc-braces-around-statements %t +// REQUIRES: shell + +void do_something(const char *) {} + +void test() { + volatile bool cond = false; + if (cond) + do_something("if"); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: statement should be inside braces + // CHECK-MESSAGES: note: FIX-IT applied suggested code changes + // CHECK-FIXES: {do_something("if");} + if (cond) { + do_something("if"); + } + + for (;;) + do_something("for"); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: statement should be inside braces + // CHECK-MESSAGES: note: FIX-IT applied suggested code changes + // CHECK-FIXES: {do_something("for");} + for (;;) { + do_something("for"); + } + +#if __cplusplus >= 201100L + int arr[4] = {1, 2, 3, 4}; + for (int a : arr) + do_something("for-range"); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: statement should be inside braces + // CHECK-MESSAGES: note: FIX-IT applied suggested code changes + // CHECK-FIXES: {do_something("for-range");} + for (int a : arr) { + do_something("for-range"); + } +#endif + + while (cond) + do_something("while"); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: statement should be inside braces + // CHECK-MESSAGES: note: FIX-IT applied suggested code changes + // CHECK-FIXES: {do_something("while");} + while (cond) { + do_something("while"); + } + + do + do_something("do"); + while (cond); + // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: statement should be inside braces + // CHECK-MESSAGES: note: FIX-IT applied suggested code changes + // CHECK-FIXES: {do_something("do");} + do { + do_something("do"); + } while (cond); +} + Index: unittests/clang-tidy/MiscModuleTest.cpp =================================================================== --- unittests/clang-tidy/MiscModuleTest.cpp +++ 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,163 @@ "void f(int xxx, int yyy); void g() { f(/*xxy=*/0, 0); }"); } +TEST(BracesAroundStatementsCheck, If) { + // if only + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " if (false) {\n" + " return -1;\n" + " }\n" + " return 0;\n" + "}"); + // if else + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " if (false) {\n" + " return -1;\n" + " } else {\n" + " return 0;\n" + " }\n" + "}"); + // if only + EXPECT_EQ("int main() {\n" + " if (false)\n" + " {return -1;}\n" + " return 0;\n" + "}", + runCheckOnCode("int main() {\n" + " if (false)\n" + " return -1;\n" + " return 0;\n" + "}")); + // if else + EXPECT_EQ("int main() {\n" + " if (false)\n" + " {return -1;}\n" + " else\n" + " {return 0;}\n" + "}", + runCheckOnCode("int main() {\n" + " if (false)\n" + " return -1;\n" + " else\n" + " return 0;\n" + "}")); + // if else if else + EXPECT_EQ("int main() {\n" + " if (false)\n" + " {return -1;}\n" + " else if (1 == 2)\n" + " {return -2;}\n" + " else\n" + " {return 0;}\n" + "}", + runCheckOnCode("int main() {\n" + " if (false)\n" + " return -1;\n" + " else if (1 == 2)\n" + " return -2;\n" + " else\n" + " return 0;\n" + "}")); + // if else if {} else + EXPECT_EQ("int main() {\n" + " if (false)\n" + " {return -1;}\n" + " else if (1 == 2) {\n" + " return -2;\n" + " } else\n" + " {return 0;}\n" + "}", + runCheckOnCode("int main() {\n" + " if (false)\n" + " return -1;\n" + " else if (1 == 2) {\n" + " return -2;\n" + " } else\n" + " return 0;\n" + "}")); +} + +TEST(BracesAroundStatementsCheck, For) { + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " for (;;) {\n" + " ;\n" + " }\n" + " return 0;\n" + "}"); + EXPECT_EQ("int main() {\n" + " for (;;)\n" + " {;}\n" + " return 0;\n" + "}", + runCheckOnCode("int main() {\n" + " for (;;)\n" + " ;\n" + " return 0;\n" + "}")); +} + +TEST(BracesAroundStatementsCheck, ForRange) { + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " int arr[4];\n" + " for (int i : arr) {\n" + " ;\n" + " }\n" + " return 0;\n" + "}"); + EXPECT_EQ("int main() {\n" + " int arr[4];\n" + " for (int i : arr)\n" + " {;}\n" + " return 0;\n" + "}", + runCheckOnCode("int main() {\n" + " int arr[4];\n" + " for (int i : arr)\n" + " ;\n" + " return 0;\n" + "}")); +} + +TEST(BracesAroundStatementsCheck, DoWhile) { + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " do {\n" + " ;\n" + " } while (false);\n" + " return 0;\n" + "}"); + EXPECT_EQ("int main() {\n" + " do\n" + " {;}\n" + " while (false);\n" + " return 0;\n" + "}", + runCheckOnCode("int main() {\n" + " do\n" + " ;\n" + " while (false);\n" + " return 0;\n" + "}")); +} + +TEST(BracesAroundStatementsCheck, While) { + EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n" + " while (false) {\n" + " ;\n" + " }\n" + " return 0;\n" + "}"); + EXPECT_EQ("int main() {\n" + " while (false)\n" + " {;}\n" + " return 0;\n" + "}", + runCheckOnCode("int main() {\n" + " while (false)\n" + " ;\n" + " return 0;\n" + "}")); +} + } // namespace test } // namespace tidy } // namespace clang