diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -113,12 +113,12 @@ } void EndOfMainFile() { - for (const auto& Entry : MainFileMacros) + for (const auto &Entry : MainFileMacros) Out->push_back(Entry.getKey()); llvm::sort(*Out); } - private: +private: const SourceManager &SM; bool InMainFile = true; llvm::StringSet<> MainFileMacros; @@ -275,12 +275,37 @@ const LangOptions &LangOpts; }; +// This is a copy of ClangTidyContext::CachedGlobList. +// FIXME: Factor out to a common place. +class CachedGlobList { +public: + CachedGlobList(StringRef Globs) : Globs(Globs) {} + + bool contains(StringRef S) { + switch (auto &Result = Cache[S]) { + case Yes: + return true; + case No: + return false; + case None: + Result = Globs.contains(S) ? Yes : No; + return Result == Yes; + } + llvm_unreachable("invalid enum"); + } + +private: + tidy::GlobList Globs; + enum Tristate { None, Yes, No }; + llvm::StringMap Cache; +}; + // A wrapper around StoreDiags to handle suppression comments for // clang-tidy diagnostics (and possibly other clang-tidy customizations in the // future). class ClangdDiagnosticConsumer : public StoreDiags { public: - ClangdDiagnosticConsumer() { + ClangdDiagnosticConsumer(llvm::Optional WarningsAsErrors) { filterDiagnostics([this](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info, bool IsInsideMainFile) { @@ -299,14 +324,36 @@ } return true; }); + + if (WarningsAsErrors) { + WarningAsErrorFilter = + llvm::make_unique(*WarningsAsErrors); + } } void setClangTidyContext(tidy::ClangTidyContext *CTContext) { this->CTContext = CTContext; } + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const clang::Diagnostic &Info) override { + DiagnosticsEngine::Level Level = DiagLevel; + + // Check for warning-as-error. + if (CTContext && WarningAsErrorFilter && + DiagLevel == DiagnosticsEngine::Warning) { + std::string CheckName = CTContext->getCheckName(Info.getID()); + if (!CheckName.empty() && WarningAsErrorFilter->contains(CheckName)) { + Level = DiagnosticsEngine::Error; + } + } + + StoreDiags::HandleDiagnostic(Level, Info); + } + private: tidy::ClangTidyContext *CTContext = nullptr; + std::unique_ptr WarningAsErrorFilter; }; } // namespace @@ -328,7 +375,7 @@ const PrecompiledPreamble *PreamblePCH = Preamble ? &Preamble->Preamble : nullptr; - ClangdDiagnosticConsumer ASTDiags; + ClangdDiagnosticConsumer ASTDiags{Opts.ClangTidyOpts.WarningsAsErrors}; std::string Content = Buffer->getBuffer(); auto Clang = prepareCompilerInstance(std::move(CI), PreamblePCH,