Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -238,7 +238,8 @@ /// Errors containing fixes are automatically applied and reformatted. If no /// clang-format configuration file is found, the given \P FormatStyle is used. void handleErrors(const std::vector &Errors, bool Fix, - StringRef FormatStyle, unsigned &WarningsAsErrorsCount); + bool FormatFixes, StringRef FormatStyle, + unsigned &WarningsAsErrorsCount); /// \brief Serializes replacements into YAML and writes them to the specified /// output stream. Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -89,13 +89,14 @@ class ErrorReporter { public: - ErrorReporter(bool ApplyFixes, StringRef FormatStyle) + ErrorReporter(bool ApplyFixes, bool FormatFixes, StringRef FormatStyle) : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()), DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), Diags(IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, DiagPrinter), - SourceMgr(Diags, Files), ApplyFixes(ApplyFixes), TotalFixes(0), - AppliedFixes(0), WarningsAsErrors(0), FormatStyle(FormatStyle) { + SourceMgr(Diags, Files), ApplyFixes(ApplyFixes), + FormatFixes(FormatFixes), TotalFixes(0), AppliedFixes(0), + WarningsAsErrors(0), FormatStyle(FormatStyle) { DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors(); DiagPrinter->BeginSourceFile(LangOpts); } @@ -183,7 +184,6 @@ } void Finish() { - // FIXME: Run clang-format on changes. if (ApplyFixes && TotalFixes > 0) { Rewriter Rewrite(SourceMgr, LangOpts); for (const auto &FileAndReplacements : FileReplacements) { @@ -209,6 +209,18 @@ llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n"; continue; } + if (FormatFixes) { + llvm::Expected FormattedReplacements = + format::formatReplacements(Code, *CleanReplacements, *Style); + if (FormattedReplacements) { + CleanReplacements = std::move(FormattedReplacements); + if (!CleanReplacements) + llvm_unreachable("!CleanReplacements"); + } else { + llvm::errs() << llvm::toString(FormattedReplacements.takeError()) + << ". Continuing without formatting.\n"; + } + } if (!tooling::applyAllReplacements(CleanReplacements.get(), Rewrite)) { llvm::errs() << "Can't apply replacements for file " << File << "\n"; } @@ -248,6 +260,7 @@ SourceManager SourceMgr; llvm::StringMap FileReplacements; bool ApplyFixes; + bool FormatFixes; unsigned TotalFixes; unsigned AppliedFixes; unsigned WarningsAsErrors; @@ -542,8 +555,9 @@ } void handleErrors(const std::vector &Errors, bool Fix, - StringRef FormatStyle, unsigned &WarningsAsErrorsCount) { - ErrorReporter Reporter(Fix, FormatStyle); + bool FormatFixes, StringRef FormatStyle, + unsigned &WarningsAsErrorsCount) { + ErrorReporter Reporter(Fix, FormatFixes, FormatStyle); vfs::FileSystem &FileSystem = *Reporter.getSourceManager().getFileManager().getVirtualFileSystem(); auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory(); Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -60,7 +60,7 @@ prefix add checks with matching names to the set, globs with the '-' prefix remove checks with matching names from the set of enabled -checks. This option's value is appended to the +checks. This option's value is appended to the value of the 'Checks' option in .clang-tidy file, if any. )"), @@ -120,6 +120,11 @@ )"), cl::init(false), cl::cat(ClangTidyCategory)); +static cl::opt Format("format", cl::desc(R"( +Format code around applied fixes. +)"), + cl::init(false), cl::cat(ClangTidyCategory)); + static cl::opt FormatStyle("style", cl::desc(R"( Fallback style for reformatting after inserting fixes if there is no clang-format config file found. @@ -189,7 +194,7 @@ cl::cat(ClangTidyCategory)); static cl::opt Quiet("quiet", cl::desc(R"( -Run clang-tidy in quiet mode. This suppresses +Run clang-tidy in quiet mode. This suppresses printing statistics about ignored warnings and warnings treated as errors if the respective options are specified. @@ -402,7 +407,7 @@ unsigned WErrorCount = 0; // -fix-errors implies -fix. - handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, FormatStyle, + handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, Format, FormatStyle, WErrorCount); if (!ExportFixes.empty() && !Errors.empty()) { Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -87,6 +87,9 @@ Finds and replaces explicit calls to the constructor in a return statement by a braced initializer list so that the return type is not needlessly repeated. +- Support clang-formatting of the code around applied fixes (``-format`` + command-line option). + Improvements to include-fixer ----------------------------- Index: docs/clang-tidy/index.rst =================================================================== --- docs/clang-tidy/index.rst +++ docs/clang-tidy/index.rst @@ -158,6 +158,8 @@ errors were found. If compiler errors have attached fix-its, clang-tidy will apply them as well. + -format - + Format code around applied fixes. -header-filter= - Regular expression matching the names of the headers to output diagnostics from. Diagnostics @@ -179,6 +181,11 @@ List all enabled checks and exit. Use with -checks=* to list all available checks. -p= - Build path + -quiet - + Run clang-tidy in quiet mode. This suppresses + printing statistics about ignored warnings and + warnings treated as errors if the respective + options are specified. -style= - Fallback style for reformatting after inserting fixes if there is no clang-format config file found. @@ -558,10 +565,10 @@ against the fixed code (i.e., the code after generated fix-its are applied). In particular, ``CHECK-FIXES:`` can be used to check that code was not modified by fix-its, by checking that it is present -unchanged in the fixed code. The full set of `FileCheck`_ directives +unchanged in the fixed code. The full set of `FileCheck`_ directives is available (e.g., ``CHECK-MESSAGES-SAME:``, ``CHECK-MESSAGES-NOT:``), though typically the basic ``CHECK`` forms (``CHECK-MESSAGES`` and ``CHECK-FIXES``) -are sufficient for clang-tidy tests. Note that the `FileCheck`_ +are sufficient for clang-tidy tests. Note that the `FileCheck`_ documentation mostly assumes the default prefix (``CHECK``), and hence describes the directive as ``CHECK:``, ``CHECK-SAME:``, ``CHECK-NOT:``, etc. Replace ``CHECK`` by either ``CHECK-FIXES`` or ``CHECK-MESSAGES`` for Index: test/clang-tidy/readability-braces-around-statements-format.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-braces-around-statements-format.cpp @@ -0,0 +1,33 @@ +// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -format -- + +void do_something(const char *) {} + +bool cond(const char *) { + return false; +} + +void test() { + if (cond("if0") /*comment*/) do_something("same-line"); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: statement should be inside braces + // CHECK-FIXES: {{^}} if (cond("if0") /*comment*/) {{{$}} + // CHECK-FIXES-NEXT: {{^}} do_something("same-line");{{$}} + // CHECK-FIXES-NEXT: {{^}} }{{$}} + + 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) {{{$}} + // CHECK-FIXES-NEXT: {{^}} while (2) { + // CHECK-FIXES-NEXT: {{^}} if (3) { + // CHECK-FIXES-NEXT: {{^}} for (;;) { + // CHECK-FIXES-NEXT: {{^}} do { + // CHECK-FIXES-NEXT: {{^}} ; + // CHECK-FIXES-NEXT: {{^}} } while (false) /**/; /**/ + // CHECK-FIXES-NEXT: {{^}} } + // CHECK-FIXES-NEXT: {{^}} } + // CHECK-FIXES-NEXT: {{^}} } + // CHECK-FIXES-NEXT: {{^}} } +}