Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -64,7 +64,7 @@ static cl::opt SystemHeaders("system-headers", - cl::desc("Display the errors from system headers"), + cl::desc("Display the errors from system headers."), cl::init(false), cl::cat(ClangTidyCategory)); static cl::opt LineFilter("line-filter", @@ -78,8 +78,18 @@ " ]"), cl::init(""), cl::cat(ClangTidyCategory)); -static cl::opt Fix("fix", cl::desc("Fix detected errors if possible."), - cl::init(false), cl::cat(ClangTidyCategory)); +static cl::opt + Fix("fix", cl::desc("Apply suggested fixes. Without -fix-errors\n" + "clang-tidy will bail out if any compilation\n" + "errors were found."), + cl::init(false), cl::cat(ClangTidyCategory)); + +static cl::opt + FixErrors("fix-errors", + cl::desc("Apply suggested fixes even if compilation errors\n" + "were found. If compiler errors have attached\n" + "fix-its, clang-tidy will apply them as well."), + cl::init(false), cl::cat(ClangTidyCategory)); static cl::opt ListChecks("list-checks", @@ -277,6 +287,19 @@ runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(), OptionsParser.getSourcePathList(), &Errors, EnableCheckProfile ? &Profile : nullptr); + bool FoundErrors = + std::find_if(Errors.begin(), Errors.end(), [](const ClangTidyError &E) { + return E.DiagLevel == ClangTidyError::Error; + }) != Errors.end(); + + // -fix-errors implies -fix. + if (FixErrors) + Fix = true; + + const bool DisableFixes = Fix && FoundErrors && !FixErrors; + if (DisableFixes) + Fix = false; + handleErrors(Errors, Fix); if (!ExportFixes.empty() && !Errors.empty()) { @@ -290,6 +313,10 @@ } printStats(Stats); + if (DisableFixes) + llvm::errs() << "Found compiler errors, but -fix-error was not specified.\n" + "Fixes have NOT been applied.\n\n"; + if (EnableCheckProfile) printProfileData(Profile, llvm::errs()); Index: test/clang-tidy/fix-errors.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fix-errors.cpp @@ -0,0 +1,15 @@ +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-tidy %t.cpp -checks='-*,google-explicit-constructor' -fix -- > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.cpp -check-prefix=CHECK-FIX %s +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-tidy %t.cpp -checks='-*,google-explicit-constructor' -fix-errors -- > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.cpp -check-prefix=CHECK-FIX2 %s +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES2 %s + +class A { A(int i); } +// CHECK-FIX: class A { A(int i); }{{$}} +// CHECK-MESSAGES: Fixes have NOT been applied. +// CHECK-FIX2: class A { explicit A(int i); }; +// CHECK-MESSAGES2: note: FIX-IT applied suggested code changes +// CHECK-MESSAGES2: clang-tidy applied 2 of 2 suggested fixes.