Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -11,6 +11,7 @@ IdentifierNamingCheck.cpp ImplicitBoolConversionCheck.cpp InconsistentDeclarationParameterNameCheck.cpp + IsolateDeclCheck.cpp MagicNumbersCheck.cpp MisleadingIndentationCheck.cpp MisplacedArrayIndexCheck.cpp Index: clang-tidy/readability/IsolateDeclCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/IsolateDeclCheck.h @@ -0,0 +1,35 @@ +//===--- IsolateDeclCheck.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_READABILITY_ISOLATEDECLCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ISOLATEDECLCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-isolate-decl.html +class IsolateDeclCheck : public ClangTidyCheck { +public: + IsolateDeclCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ISOLATEDECLCHECK_H Index: clang-tidy/readability/IsolateDeclCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/IsolateDeclCheck.cpp @@ -0,0 +1,79 @@ +//===--- IsolateDeclCheck.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 "IsolateDeclCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +namespace { +AST_MATCHER(DeclStmt, isSingleDecl) { return Node.isSingleDecl(); } +} // namespace + +void IsolateDeclCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(declStmt(unless(isSingleDecl())).bind("decl_stmt"), this); +} + +namespace { +std::string GetIsolatedDecl(const VarDecl *D, const SourceManager &SM, + const LangOptions &LangOpts) { + QualType VarType = D->getType(); + PrintingPolicy TypePrinter(LangOpts); + + std::string TypeAndName = + VarType.getAsString(TypePrinter) + " " + D->getNameAsString(); + std::string Initializer = ""; + + if (D->hasInit()) { + SourceRange InclusiveRange(D->getInit()->getBeginLoc(), + D->getInit()->getEndLoc().getLocWithOffset(2)); + assert(InclusiveRange.isValid() && "Invalid Source Range created"); + + CharSourceRange R = Lexer::getAsCharRange(InclusiveRange, SM, LangOpts); + assert(R.isValid() && "Retrieved invalid char source range"); + + bool InvalidText = false; + Initializer = Lexer::getSourceText(R, SM, LangOpts, &InvalidText).str(); + assert(!InvalidText && "Retrieved invalid text"); + + return TypeAndName + " = " + Initializer + ";"; + } + + return TypeAndName + ";"; +} +} // namespace + +void IsolateDeclCheck::check(const MatchFinder::MatchResult &Result) { + const auto *WholeDecl = Result.Nodes.getNodeAs("decl_stmt"); + std::string Replacement = ""; + + for (const Decl *D : WholeDecl->decls()) { + const auto *VD = dyn_cast(D); + if (VD == nullptr) { + Replacement.clear(); + break; + } + Replacement += GetIsolatedDecl(VD, *Result.SourceManager, getLangOpts()); + } + auto Diag = + diag(WholeDecl->getBeginLoc(), "make only one declaration per statement"); + + if (!Replacement.empty()) + Diag << FixItHint::CreateReplacement(WholeDecl->getSourceRange(), + Replacement); +} +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -20,6 +20,7 @@ #include "IdentifierNamingCheck.h" #include "ImplicitBoolConversionCheck.h" #include "InconsistentDeclarationParameterNameCheck.h" +#include "IsolateDeclCheck.h" #include "MagicNumbersCheck.h" #include "MisleadingIndentationCheck.h" #include "MisplacedArrayIndexCheck.h" @@ -66,6 +67,8 @@ "readability-implicit-bool-conversion"); CheckFactories.registerCheck( "readability-inconsistent-declaration-parameter-name"); + CheckFactories.registerCheck( + "readability-isolate-decl"); CheckFactories.registerCheck( "readability-magic-numbers"); CheckFactories.registerCheck( Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -93,6 +93,11 @@ Flags uses of ``absl::StrCat()`` to append to a ``std::string``. Suggests ``absl::StrAppend()`` should be used instead. +- New :doc:`readability-isolate-decl + ` check. + + FIXME: add release notes. + - New :doc:`readability-magic-numbers ` check. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -225,6 +225,7 @@ readability-identifier-naming readability-implicit-bool-conversion readability-inconsistent-declaration-parameter-name + readability-isolate-decl readability-magic-numbers readability-misleading-indentation readability-misplaced-array-index Index: docs/clang-tidy/checks/readability-isolate-decl.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-isolate-decl.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - readability-isolate-decl + +readability-isolate-decl +======================== + +FIXME: Describe what patterns does the check detect and why. Give examples. Index: test/clang-tidy/readability-isolate-decl.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-isolate-decl.cpp @@ -0,0 +1,65 @@ +// RUN: %check_clang_tidy %s readability-isolate-decl %t + +void f() { + int i; +} + +void f2() { + int i, j, *k, lala = 42; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: int i;int j;int * k;int lala = 42; + // + int normal, weird = /* comment */ 42; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: int normal;int weird = 42; +} + +void f3() { + int i, *pointer1; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: int i;int * pointer1; + // + int *pointer2 = nullptr, *pointer3 = &i; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: int * pointer2 = nullpt;int * pointer3 = &i; +} + +void f4() { + // clang-format off + double d = 42./* foo */, z = 43., /* hi */ y, c /* */ /* */, l = 2.; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: double d = 42;double z = 43;double y;double c;double l = 2.; + // clang-format on +} + +struct SomeClass { + SomeClass() = default; + SomeClass(int value); +}; +void f5() { + SomeClass v1, v2(42), v3{42}, v4(42.5); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: SomeClass v1 = v1;SomeClass v2 = v2(42);SomeClass v3 = v3{42};SomeClass v4 = v4(42.5); + + SomeClass v5 = 42, *p1 = nullptr; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: SomeClass v5 = v5 = 42;SomeClass * p1 = nullpt; +} + +void f6() { + int array1[] = {1, 2, 3, 4}, array2[] = {1, 2, 3}, value1, value2 = 42; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: int [4] array1 = {1, 2, 3, 4};int [3] array2 = {1, 2, 3};int value1;int value2 = 42; +} + +template +struct TemplatedType { + TemplatedType() = default; + TemplatedType(T value); +}; + +void f7() { + TemplatedType TT1(42), TT2{42}, TT3; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: make only one declaration per statement + // CHECK-FIXES: TemplatedType TT1 = TT1(42);TemplatedType TT2 = TT2{42};TemplatedType TT3 = TT; +}