Teach clang-tidy how to upgrade warnings into errors.
Similar in format to the `-checks=` argument, this new `-warnings-as-errors=`
argument upgrades any warnings emitted by the former to errors.
http://reviews.llvm.org/D15528
llvm-svn: 257642
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 0b9895b..66ab56a 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -101,7 +101,8 @@
Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
DiagPrinter),
SourceMgr(Diags, Files), Rewrite(SourceMgr, LangOpts),
- ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0) {
+ ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0),
+ WarningsAsErrors(0) {
DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
DiagPrinter->BeginSourceFile(LangOpts);
}
@@ -114,8 +115,14 @@
SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
{
auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
+ std::string Name = Error.CheckName;
+ if (Error.IsWarningAsError) {
+ Name += ",-warnings-as-errors";
+ Level = DiagnosticsEngine::Error;
+ WarningsAsErrors++;
+ }
auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
- << Message.Message << Error.CheckName;
+ << Message.Message << Name;
for (const tooling::Replacement &Fix : Error.Fix) {
SourceLocation FixLoc = getLocation(Fix.getFilePath(), Fix.getOffset());
SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
@@ -147,6 +154,8 @@
}
}
+ unsigned getWarningsAsErrorsCount() const { return WarningsAsErrors; }
+
private:
SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
if (FilePath.empty())
@@ -174,6 +183,7 @@
bool ApplyFixes;
unsigned TotalFixes;
unsigned AppliedFixes;
+ unsigned WarningsAsErrors;
};
class ClangTidyASTConsumer : public MultiplexConsumer {
@@ -421,11 +431,13 @@
return Context.getStats();
}
-void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix) {
+void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix,
+ unsigned &WarningsAsErrorsCount) {
ErrorReporter Reporter(Fix);
for (const ClangTidyError &Error : Errors)
Reporter.reportDiagnostic(Error);
Reporter.Finish();
+ WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount();
}
void exportReplacements(const std::vector<ClangTidyError> &Errors,
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h
index a2dbcbc..f01bbad 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -214,7 +214,8 @@
//
/// \brief Displays the found \p Errors to the users. If \p Fix is true, \p
/// Errors containing fixes are automatically applied.
-void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix);
+void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix,
+ unsigned &WarningsAsErrorsCount);
/// \brief Serializes replacements into YAML and writes them to the specified
/// output stream.
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index ac21675..320a50a 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -115,8 +115,10 @@
}
ClangTidyError::ClangTidyError(StringRef CheckName,
- ClangTidyError::Level DiagLevel)
- : CheckName(CheckName), DiagLevel(DiagLevel) {}
+ ClangTidyError::Level DiagLevel,
+ bool IsWarningAsError)
+ : CheckName(CheckName), DiagLevel(DiagLevel),
+ IsWarningAsError(IsWarningAsError) {}
// Returns true if GlobList starts with the negative indicator ('-'), removes it
// from the GlobList.
@@ -204,6 +206,7 @@
CurrentFile = File;
CurrentOptions = getOptionsForFile(CurrentFile);
CheckFilter.reset(new GlobList(*getOptions().Checks));
+ WarningAsErrorFilter.reset(new GlobList(*getOptions().WarningsAsErrors));
}
void ClangTidyContext::setASTContext(ASTContext *Context) {
@@ -237,6 +240,11 @@
return CheckFilter->contains(CheckName);
}
+GlobList &ClangTidyContext::getWarningAsErrorFilter() {
+ assert(WarningAsErrorFilter != nullptr);
+ return *WarningAsErrorFilter;
+}
+
/// \brief Store a \c ClangTidyError.
void ClangTidyContext::storeError(const ClangTidyError &Error) {
Errors.push_back(Error);
@@ -324,7 +332,10 @@
LastErrorRelatesToUserCode = true;
LastErrorPassesLineFilter = true;
}
- Errors.push_back(ClangTidyError(CheckName, Level));
+ bool IsWarningAsError =
+ DiagLevel == DiagnosticsEngine::Warning &&
+ Context.getWarningAsErrorFilter().contains(CheckName);
+ Errors.push_back(ClangTidyError(CheckName, Level, IsWarningAsError));
}
// FIXME: Provide correct LangOptions for each file.
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index 780f8a3..420f8f4 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -57,7 +57,7 @@
Error = DiagnosticsEngine::Error
};
- ClangTidyError(StringRef CheckName, Level DiagLevel);
+ ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError);
std::string CheckName;
ClangTidyMessage Message;
@@ -65,6 +65,7 @@
SmallVector<ClangTidyMessage, 1> Notes;
Level DiagLevel;
+ bool IsWarningAsError;
};
/// \brief Read-only set of strings represented as a list of positive and
@@ -164,6 +165,10 @@
/// \brief Returns true if the check name is enabled for the \c CurrentFile.
bool isCheckEnabled(StringRef CheckName) const;
+ /// \brief Returns check filter for the \c CurrentFile which
+ /// selects checks for upgrade to error.
+ GlobList &getWarningAsErrorFilter();
+
/// \brief Returns global options.
const ClangTidyGlobalOptions &getGlobalOptions() const;
@@ -211,6 +216,7 @@
std::string CurrentFile;
ClangTidyOptions CurrentOptions;
std::unique_ptr<GlobList> CheckFilter;
+ std::unique_ptr<GlobList> WarningAsErrorFilter;
LangOptions LangOpts;
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 6baca37..9f6be18 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -85,6 +85,7 @@
MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(
IO, Options.CheckOptions);
IO.mapOptional("Checks", Options.Checks);
+ IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors);
IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
IO.mapOptional("AnalyzeTemporaryDtors", Options.AnalyzeTemporaryDtors);
IO.mapOptional("User", Options.User);
@@ -103,6 +104,7 @@
ClangTidyOptions ClangTidyOptions::getDefaults() {
ClangTidyOptions Options;
Options.Checks = "";
+ Options.WarningsAsErrors = "";
Options.HeaderFilterRegex = "";
Options.SystemHeaders = false;
Options.AnalyzeTemporaryDtors = false;
@@ -123,6 +125,12 @@
Result.Checks =
(Result.Checks && !Result.Checks->empty() ? *Result.Checks + "," : "") +
*Other.Checks;
+ if (Other.WarningsAsErrors)
+ Result.WarningsAsErrors =
+ (Result.WarningsAsErrors && !Result.WarningsAsErrors->empty()
+ ? *Result.WarningsAsErrors + ","
+ : "") +
+ *Other.WarningsAsErrors;
if (Other.HeaderFilterRegex)
Result.HeaderFilterRegex = Other.HeaderFilterRegex;
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index b3d956f..10619cc 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -62,6 +62,9 @@
/// \brief Checks filter.
llvm::Optional<std::string> Checks;
+ /// \brief WarningsAsErrors filter.
+ llvm::Optional<std::string> WarningsAsErrors;
+
/// \brief Output warnings from headers matching this filter. Warnings from
/// main files will always be displayed.
llvm::Optional<std::string> HeaderFilterRegex;
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index c5f57b1..8bcff12 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -64,15 +64,21 @@
cl::init(""), cl::cat(ClangTidyCategory));
static cl::opt<std::string>
-HeaderFilter("header-filter",
- cl::desc("Regular expression matching the names of the\n"
- "headers to output diagnostics from. Diagnostics\n"
- "from the main file of each translation unit are\n"
- "always displayed.\n"
- "Can be used together with -line-filter.\n"
- "This option overrides the value read from a\n"
- ".clang-tidy file."),
- cl::init(""), cl::cat(ClangTidyCategory));
+ WarningsAsErrors("warnings-as-errors",
+ cl::desc("Upgrades warnings to errors. "
+ "Same format as '-checks'."),
+ cl::init(""), cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string>
+ HeaderFilter("header-filter",
+ cl::desc("Regular expression matching the names of the\n"
+ "headers to output diagnostics from. Diagnostics\n"
+ "from the main file of each translation unit are\n"
+ "always displayed.\n"
+ "Can be used together with -line-filter.\n"
+ "This option overrides the value read from a\n"
+ ".clang-tidy file."),
+ cl::init(""), cl::cat(ClangTidyCategory));
static cl::opt<bool>
SystemHeaders("system-headers",
@@ -227,6 +233,7 @@
ClangTidyOptions DefaultOptions;
DefaultOptions.Checks = DefaultChecks;
+ DefaultOptions.WarningsAsErrors = "";
DefaultOptions.HeaderFilterRegex = HeaderFilter;
DefaultOptions.SystemHeaders = SystemHeaders;
DefaultOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
@@ -238,6 +245,8 @@
ClangTidyOptions OverrideOptions;
if (Checks.getNumOccurrences() > 0)
OverrideOptions.Checks = Checks;
+ if (WarningsAsErrors.getNumOccurrences() > 0)
+ OverrideOptions.WarningsAsErrors = WarningsAsErrors;
if (HeaderFilter.getNumOccurrences() > 0)
OverrideOptions.HeaderFilterRegex = HeaderFilter;
if (SystemHeaders.getNumOccurrences() > 0)
@@ -322,8 +331,10 @@
const bool DisableFixes = Fix && FoundErrors && !FixErrors;
+ unsigned WErrorCount = 0;
+
// -fix-errors implies -fix.
- handleErrors(Errors, (FixErrors || Fix) && !DisableFixes);
+ handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, WErrorCount);
if (!ExportFixes.empty() && !Errors.empty()) {
std::error_code EC;
@@ -344,6 +355,13 @@
if (EnableCheckProfile)
printProfileData(Profile, llvm::errs());
+ if (WErrorCount) {
+ StringRef Plural = WErrorCount == 1 ? "" : "s";
+ llvm::errs() << WErrorCount << " warning" << Plural << " treated as error"
+ << Plural << "\n";
+ return WErrorCount;
+ }
+
return 0;
}