carlosgalvezp created this revision.
carlosgalvezp added reviewers: aaron.ballman, whisperity.
Herald added subscribers: rnkovacs, xazax.hun, mgorny.
carlosgalvezp requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Currently, ClangTidyDiagnosticConsumer defines 2 additional
classes: ClangTidyContext and ClangTidyError. A reader does
not expect them to be there, and a file needing only one
of them needs to include the heavy ClangTidyDiangosticConsumer.h,
increasing compilation time.

Refactor by moving these classes into their own set of .h/.cpp files.
Besides readability, compilation time is also improved.
Adjust includes accordingly.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113848

Files:
  clang-tools-extra/clang-tidy/CMakeLists.txt
  clang-tools-extra/clang-tidy/ClangTidy.cpp
  clang-tools-extra/clang-tidy/ClangTidyCheck.h
  clang-tools-extra/clang-tidy/ClangTidyContext.cpp
  clang-tools-extra/clang-tidy/ClangTidyContext.h
  clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
  clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
  clang-tools-extra/clang-tidy/ClangTidyError.cpp
  clang-tools-extra/clang-tidy/ClangTidyError.h
  clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
  clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
  clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h

Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===================================================================
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -12,6 +12,7 @@
 #include "ClangTidy.h"
 #include "ClangTidyCheck.h"
 #include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyError.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
Index: clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -1,6 +1,7 @@
 #include "ClangTidyOptions.h"
 #include "ClangTidyCheck.h"
 #include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyError.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Testing/Support/Annotations.h"
Index: clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
===================================================================
--- clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -16,6 +16,8 @@
 
 #include "ClangTidyMain.h"
 #include "../ClangTidy.h"
+#include "../ClangTidyContext.h"
+#include "../ClangTidyError.h"
 #include "../ClangTidyForceLinker.h"
 #include "../GlobList.h"
 #include "clang/Tooling/CommonOptionsParser.h"
@@ -128,10 +130,10 @@
                                cl::init(false), cl::cat(ClangTidyCategory));
 
 static cl::opt<bool> FixNotes("fix-notes", cl::desc(R"(
-If a warning has no fix, but a single fix can 
-be found through an associated diagnostic note, 
-apply the fix. 
-Specifying this flag will implicitly enable the 
+If a warning has no fix, but a single fix can
+be found through an associated diagnostic note,
+apply the fix.
+Specifying this flag will implicitly enable the
 '--fix' flag.
 )"),
                               cl::init(false), cl::cat(ClangTidyCategory));
Index: clang-tools-extra/clang-tidy/ClangTidyError.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ClangTidyError.h
@@ -0,0 +1,38 @@
+//===--- ClangTidyError.h - clang-tidy --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYERROR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYERROR_H
+
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+
+/// A detected error complete with information to display diagnostic and
+/// automatic fix.
+///
+/// This is used as an intermediate format to transport Diagnostics without a
+/// dependency on a SourceManager.
+///
+/// FIXME: Make Diagnostics flexible enough to support this directly.
+struct ClangTidyError : tooling::Diagnostic {
+  ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
+                 bool IsWarningAsError);
+
+  bool IsWarningAsError;
+  std::vector<std::string> EnabledDiagnosticAliases;
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
Index: clang-tools-extra/clang-tidy/ClangTidyError.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ClangTidyError.cpp
@@ -0,0 +1,25 @@
+//===--- tools/extra/clang-tidy/ClangTidyError.cpp -----------------------=== //
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file This file implements the ClangTidyErrorDiagnosticConsumer class.
+///
+///  This tool uses the Clang Tooling infrastructure, see
+///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+///  for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyError.h"
+using namespace clang;
+using namespace tidy;
+
+ClangTidyError::ClangTidyError(StringRef CheckName,
+                               ClangTidyError::Level DiagLevel,
+                               StringRef BuildDirectory, bool IsWarningAsError)
+    : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory),
+      IsWarningAsError(IsWarningAsError) {}
Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -9,11 +9,8 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
 
-#include "ClangTidyOptions.h"
-#include "ClangTidyProfiling.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Tooling/Core/Diagnostic.h"
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/Regex.h"
 
 namespace clang {
@@ -29,190 +26,8 @@
 } // namespace tooling
 
 namespace tidy {
-
-/// A detected error complete with information to display diagnostic and
-/// automatic fix.
-///
-/// This is used as an intermediate format to transport Diagnostics without a
-/// dependency on a SourceManager.
-///
-/// FIXME: Make Diagnostics flexible enough to support this directly.
-struct ClangTidyError : tooling::Diagnostic {
-  ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
-                 bool IsWarningAsError);
-
-  bool IsWarningAsError;
-  std::vector<std::string> EnabledDiagnosticAliases;
-};
-
-/// Contains displayed and ignored diagnostic counters for a ClangTidy
-/// run.
-struct ClangTidyStats {
-  ClangTidyStats()
-      : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
-        ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
-
-  unsigned ErrorsDisplayed;
-  unsigned ErrorsIgnoredCheckFilter;
-  unsigned ErrorsIgnoredNOLINT;
-  unsigned ErrorsIgnoredNonUserCode;
-  unsigned ErrorsIgnoredLineFilter;
-
-  unsigned errorsIgnored() const {
-    return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
-           ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
-  }
-};
-
-/// Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
-/// provided by this context.
-///
-/// A \c ClangTidyCheck always has access to the active context to report
-/// warnings like:
-/// \code
-/// Context->Diag(Loc, "Single-argument constructors must be explicit")
-///     << FixItHint::CreateInsertion(Loc, "explicit ");
-/// \endcode
-class ClangTidyContext {
-public:
-  /// Initializes \c ClangTidyContext instance.
-  ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
-                   bool AllowEnablingAnalyzerAlphaCheckers = false);
-  /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
-  // FIXME: this is required initialization, and should be a constructor param.
-  // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
-    this->DiagEngine = DiagEngine;
-  }
-
-  ~ClangTidyContext();
-
-  /// Report any errors detected using this method.
-  ///
-  /// This is still under heavy development and will likely change towards using
-  /// tablegen'd diagnostic IDs.
-  /// FIXME: Figure out a way to manage ID spaces.
-  DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
-                         StringRef Message,
-                         DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
-
-  DiagnosticBuilder diag(StringRef CheckName, StringRef Message,
-                         DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
-
-  DiagnosticBuilder diag(const ClangTidyError &Error);
-
-  /// Report any errors to do with reading the configuration using this method.
-  DiagnosticBuilder
-  configurationDiag(StringRef Message,
-                    DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
-
-  /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
-  ///
-  /// This is called from the \c ClangTidyCheck base class.
-  void setSourceManager(SourceManager *SourceMgr);
-
-  /// Should be called when starting to process new translation unit.
-  void setCurrentFile(StringRef File);
-
-  /// Returns the main file name of the current translation unit.
-  StringRef getCurrentFile() const { return CurrentFile; }
-
-  /// Sets ASTContext for the current translation unit.
-  void setASTContext(ASTContext *Context);
-
-  /// Gets the language options from the AST context.
-  const LangOptions &getLangOpts() const { return LangOpts; }
-
-  /// Returns the name of the clang-tidy check which produced this
-  /// diagnostic ID.
-  std::string getCheckName(unsigned DiagnosticID) const;
-
-  /// Returns \c true if the check is enabled for the \c CurrentFile.
-  ///
-  /// The \c CurrentFile can be changed using \c setCurrentFile.
-  bool isCheckEnabled(StringRef CheckName) const;
-
-  /// Returns \c true if the check should be upgraded to error for the
-  /// \c CurrentFile.
-  bool treatAsError(StringRef CheckName) const;
-
-  /// Returns global options.
-  const ClangTidyGlobalOptions &getGlobalOptions() const;
-
-  /// Returns options for \c CurrentFile.
-  ///
-  /// The \c CurrentFile can be changed using \c setCurrentFile.
-  const ClangTidyOptions &getOptions() const;
-
-  /// Returns options for \c File. Does not change or depend on
-  /// \c CurrentFile.
-  ClangTidyOptions getOptionsForFile(StringRef File) const;
-
-  /// Returns \c ClangTidyStats containing issued and ignored diagnostic
-  /// counters.
-  const ClangTidyStats &getStats() const { return Stats; }
-
-  /// Control profile collection in clang-tidy.
-  void setEnableProfiling(bool Profile);
-  bool getEnableProfiling() const { return Profile; }
-
-  /// Control storage of profile date.
-  void setProfileStoragePrefix(StringRef ProfilePrefix);
-  llvm::Optional<ClangTidyProfiling::StorageParams>
-  getProfileStorageParams() const;
-
-  /// Should be called when starting to process new translation unit.
-  void setCurrentBuildDirectory(StringRef BuildDirectory) {
-    CurrentBuildDirectory = std::string(BuildDirectory);
-  }
-
-  /// Returns build directory of the current translation unit.
-  const std::string &getCurrentBuildDirectory() const {
-    return CurrentBuildDirectory;
-  }
-
-  /// If the experimental alpha checkers from the static analyzer can be
-  /// enabled.
-  bool canEnableAnalyzerAlphaCheckers() const {
-    return AllowEnablingAnalyzerAlphaCheckers;
-  }
-
-  using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
-  DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID,
-                                                       SourceLocation Loc) {
-    return DiagLevelAndFormatString(
-        static_cast<DiagnosticIDs::Level>(
-            DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
-        std::string(
-            DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID)));
-  }
-
-private:
-  // Writes to Stats.
-  friend class ClangTidyDiagnosticConsumer;
-
-  DiagnosticsEngine *DiagEngine;
-  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
-
-  std::string CurrentFile;
-  ClangTidyOptions CurrentOptions;
-  class CachedGlobList;
-  std::unique_ptr<CachedGlobList> CheckFilter;
-  std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
-
-  LangOptions LangOpts;
-
-  ClangTidyStats Stats;
-
-  std::string CurrentBuildDirectory;
-
-  llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
-
-  bool Profile;
-  std::string ProfilePrefix;
-
-  bool AllowEnablingAnalyzerAlphaCheckers;
-};
+class ClangTidyContext;
+struct ClangTidyError;
 
 /// Check whether a given diagnostic should be suppressed due to the presence
 /// of a "NOLINT" suppression comment.
Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -6,8 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
-///  \file This file implements ClangTidyDiagnosticConsumer, ClangTidyContext
-///  and ClangTidyError classes.
+///  \file This file implements the ClangTidyDiagnosticConsumer class.
 ///
 ///  This tool uses the Clang Tooling infrastructure, see
 ///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
@@ -16,6 +15,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyContext.h"
+#include "ClangTidyError.h"
 #include "ClangTidyOptions.h"
 #include "GlobList.h"
 #include "clang/AST/ASTContext.h"
@@ -143,152 +144,6 @@
 };
 } // end anonymous namespace
 
-ClangTidyError::ClangTidyError(StringRef CheckName,
-                               ClangTidyError::Level DiagLevel,
-                               StringRef BuildDirectory, bool IsWarningAsError)
-    : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory),
-      IsWarningAsError(IsWarningAsError) {}
-
-class ClangTidyContext::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:
-  GlobList Globs;
-  enum Tristate { None, Yes, No };
-  llvm::StringMap<Tristate> Cache;
-};
-
-ClangTidyContext::ClangTidyContext(
-    std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
-    bool AllowEnablingAnalyzerAlphaCheckers)
-    : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
-      Profile(false),
-      AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers) {
-  // Before the first translation unit we can get errors related to command-line
-  // parsing, use empty string for the file name in this case.
-  setCurrentFile("");
-}
-
-ClangTidyContext::~ClangTidyContext() = default;
-
-DiagnosticBuilder ClangTidyContext::diag(
-    StringRef CheckName, SourceLocation Loc, StringRef Description,
-    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
-  assert(Loc.isValid());
-  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
-      Level, (Description + " [" + CheckName + "]").str());
-  CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
-  return DiagEngine->Report(Loc, ID);
-}
-
-DiagnosticBuilder ClangTidyContext::diag(
-    StringRef CheckName, StringRef Description,
-    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
-  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
-      Level, (Description + " [" + CheckName + "]").str());
-  CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
-  return DiagEngine->Report(ID);
-}
-
-DiagnosticBuilder ClangTidyContext::diag(const ClangTidyError &Error) {
-  SourceManager &SM = DiagEngine->getSourceManager();
-  llvm::ErrorOr<const FileEntry *> File =
-      SM.getFileManager().getFile(Error.Message.FilePath);
-  FileID ID = SM.getOrCreateFileID(*File, SrcMgr::C_User);
-  SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID);
-  SourceLocation Loc = FileStartLoc.getLocWithOffset(Error.Message.FileOffset);
-  return diag(Error.DiagnosticName, Loc, Error.Message.Message,
-              static_cast<DiagnosticIDs::Level>(Error.DiagLevel));
-}
-
-DiagnosticBuilder ClangTidyContext::configurationDiag(
-    StringRef Message,
-    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
-  return diag("clang-tidy-config", Message, Level);
-}
-
-void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
-  DiagEngine->setSourceManager(SourceMgr);
-}
-
-void ClangTidyContext::setCurrentFile(StringRef File) {
-  CurrentFile = std::string(File);
-  CurrentOptions = getOptionsForFile(CurrentFile);
-  CheckFilter = std::make_unique<CachedGlobList>(*getOptions().Checks);
-  WarningAsErrorFilter =
-      std::make_unique<CachedGlobList>(*getOptions().WarningsAsErrors);
-}
-
-void ClangTidyContext::setASTContext(ASTContext *Context) {
-  DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
-  LangOpts = Context->getLangOpts();
-}
-
-const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
-  return OptionsProvider->getGlobalOptions();
-}
-
-const ClangTidyOptions &ClangTidyContext::getOptions() const {
-  return CurrentOptions;
-}
-
-ClangTidyOptions ClangTidyContext::getOptionsForFile(StringRef File) const {
-  // Merge options on top of getDefaults() as a safeguard against options with
-  // unset values.
-  return ClangTidyOptions::getDefaults().merge(
-      OptionsProvider->getOptions(File), 0);
-}
-
-void ClangTidyContext::setEnableProfiling(bool P) { Profile = P; }
-
-void ClangTidyContext::setProfileStoragePrefix(StringRef Prefix) {
-  ProfilePrefix = std::string(Prefix);
-}
-
-llvm::Optional<ClangTidyProfiling::StorageParams>
-ClangTidyContext::getProfileStorageParams() const {
-  if (ProfilePrefix.empty())
-    return llvm::None;
-
-  return ClangTidyProfiling::StorageParams(ProfilePrefix, CurrentFile);
-}
-
-bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const {
-  assert(CheckFilter != nullptr);
-  return CheckFilter->contains(CheckName);
-}
-
-bool ClangTidyContext::treatAsError(StringRef CheckName) const {
-  assert(WarningAsErrorFilter != nullptr);
-  return WarningAsErrorFilter->contains(CheckName);
-}
-
-std::string ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
-  std::string ClangWarningOption = std::string(
-      DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
-  if (!ClangWarningOption.empty())
-    return "clang-diagnostic-" + ClangWarningOption;
-  llvm::DenseMap<unsigned, std::string>::const_iterator I =
-      CheckNamesByDiagnosticID.find(DiagnosticID);
-  if (I != CheckNamesByDiagnosticID.end())
-    return I->second;
-  return "";
-}
-
 ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(
     ClangTidyContext &Ctx, DiagnosticsEngine *ExternalDiagEngine,
     bool RemoveIncompatibleErrors, bool GetFixesFromNotes)
Index: clang-tools-extra/clang-tidy/ClangTidyContext.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ClangTidyContext.h
@@ -0,0 +1,199 @@
+//===--- ClangTidyContext.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H
+
+#include "ClangTidyOptions.h"
+#include "ClangTidyProfiling.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+
+class ASTContext;
+class SourceManager;
+
+namespace tidy {
+struct ClangTidyError;
+
+/// Contains displayed and ignored diagnostic counters for a ClangTidy
+/// run.
+struct ClangTidyStats {
+  ClangTidyStats()
+      : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
+        ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
+
+  unsigned ErrorsDisplayed;
+  unsigned ErrorsIgnoredCheckFilter;
+  unsigned ErrorsIgnoredNOLINT;
+  unsigned ErrorsIgnoredNonUserCode;
+  unsigned ErrorsIgnoredLineFilter;
+
+  unsigned errorsIgnored() const {
+    return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
+           ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
+  }
+};
+
+/// Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
+/// provided by this context.
+///
+/// A \c ClangTidyCheck always has access to the active context to report
+/// warnings like:
+/// \code
+/// Context->Diag(Loc, "Single-argument constructors must be explicit")
+///     << FixItHint::CreateInsertion(Loc, "explicit ");
+/// \endcode
+class ClangTidyContext {
+public:
+  /// Initializes \c ClangTidyContext instance.
+  ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
+                   bool AllowEnablingAnalyzerAlphaCheckers = false);
+  /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
+  // FIXME: this is required initialization, and should be a constructor param.
+  // Fix the context -> diag engine -> consumer -> context initialization cycle.
+  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
+    this->DiagEngine = DiagEngine;
+  }
+
+  ~ClangTidyContext();
+
+  /// Report any errors detected using this method.
+  ///
+  /// This is still under heavy development and will likely change towards using
+  /// tablegen'd diagnostic IDs.
+  /// FIXME: Figure out a way to manage ID spaces.
+  DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
+                         StringRef Message,
+                         DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
+
+  DiagnosticBuilder diag(StringRef CheckName, StringRef Message,
+                         DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
+
+  DiagnosticBuilder diag(const ClangTidyError &Error);
+
+  /// Report any errors to do with reading the configuration using this method.
+  DiagnosticBuilder
+  configurationDiag(StringRef Message,
+                    DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
+
+  /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
+  ///
+  /// This is called from the \c ClangTidyCheck base class.
+  void setSourceManager(SourceManager *SourceMgr);
+
+  /// Should be called when starting to process new translation unit.
+  void setCurrentFile(StringRef File);
+
+  /// Returns the main file name of the current translation unit.
+  StringRef getCurrentFile() const { return CurrentFile; }
+
+  /// Sets ASTContext for the current translation unit.
+  void setASTContext(ASTContext *Context);
+
+  /// Gets the language options from the AST context.
+  const LangOptions &getLangOpts() const { return LangOpts; }
+
+  /// Returns the name of the clang-tidy check which produced this
+  /// diagnostic ID.
+  std::string getCheckName(unsigned DiagnosticID) const;
+
+  /// Returns \c true if the check is enabled for the \c CurrentFile.
+  ///
+  /// The \c CurrentFile can be changed using \c setCurrentFile.
+  bool isCheckEnabled(StringRef CheckName) const;
+
+  /// Returns \c true if the check should be upgraded to error for the
+  /// \c CurrentFile.
+  bool treatAsError(StringRef CheckName) const;
+
+  /// Returns global options.
+  const ClangTidyGlobalOptions &getGlobalOptions() const;
+
+  /// Returns options for \c CurrentFile.
+  ///
+  /// The \c CurrentFile can be changed using \c setCurrentFile.
+  const ClangTidyOptions &getOptions() const;
+
+  /// Returns options for \c File. Does not change or depend on
+  /// \c CurrentFile.
+  ClangTidyOptions getOptionsForFile(StringRef File) const;
+
+  /// Returns \c ClangTidyStats containing issued and ignored diagnostic
+  /// counters.
+  const ClangTidyStats &getStats() const { return Stats; }
+
+  /// Control profile collection in clang-tidy.
+  void setEnableProfiling(bool Profile);
+  bool getEnableProfiling() const { return Profile; }
+
+  /// Control storage of profile date.
+  void setProfileStoragePrefix(StringRef ProfilePrefix);
+  llvm::Optional<ClangTidyProfiling::StorageParams>
+  getProfileStorageParams() const;
+
+  /// Should be called when starting to process new translation unit.
+  void setCurrentBuildDirectory(StringRef BuildDirectory) {
+    CurrentBuildDirectory = std::string(BuildDirectory);
+  }
+
+  /// Returns build directory of the current translation unit.
+  const std::string &getCurrentBuildDirectory() const {
+    return CurrentBuildDirectory;
+  }
+
+  /// If the experimental alpha checkers from the static analyzer can be
+  /// enabled.
+  bool canEnableAnalyzerAlphaCheckers() const {
+    return AllowEnablingAnalyzerAlphaCheckers;
+  }
+
+  using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
+  DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID,
+                                                       SourceLocation Loc) {
+    return DiagLevelAndFormatString(
+        static_cast<DiagnosticIDs::Level>(
+            DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
+        std::string(
+            DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID)));
+  }
+
+private:
+  // Writes to Stats.
+  friend class ClangTidyDiagnosticConsumer;
+
+  DiagnosticsEngine *DiagEngine;
+  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
+
+  std::string CurrentFile;
+  ClangTidyOptions CurrentOptions;
+  class CachedGlobList;
+  std::unique_ptr<CachedGlobList> CheckFilter;
+  std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
+
+  LangOptions LangOpts;
+
+  ClangTidyStats Stats;
+
+  std::string CurrentBuildDirectory;
+
+  llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
+
+  bool Profile;
+  std::string ProfilePrefix;
+
+  bool AllowEnablingAnalyzerAlphaCheckers;
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H
Index: clang-tools-extra/clang-tidy/ClangTidyContext.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ClangTidyContext.cpp
@@ -0,0 +1,181 @@
+//===--- tools/extra/clang-tidy/ClangTidyContext.cpp ---------------------=== //
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file This file implements the ClangTidyContext class.
+///
+///  This tool uses the Clang Tooling infrastructure, see
+///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+///  for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyContext.h"
+#include "ClangTidyError.h"
+#include "ClangTidyOptions.h"
+#include "GlobList.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Regex.h"
+#include <tuple>
+#include <utility>
+#include <vector>
+using namespace clang;
+using namespace tidy;
+
+class ClangTidyContext::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:
+  GlobList Globs;
+  enum Tristate { None, Yes, No };
+  llvm::StringMap<Tristate> Cache;
+};
+
+ClangTidyContext::ClangTidyContext(
+    std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
+    bool AllowEnablingAnalyzerAlphaCheckers)
+    : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
+      Profile(false),
+      AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers) {
+  // Before the first translation unit we can get errors related to command-line
+  // parsing, use empty string for the file name in this case.
+  setCurrentFile("");
+}
+
+ClangTidyContext::~ClangTidyContext() = default;
+
+DiagnosticBuilder ClangTidyContext::diag(
+    StringRef CheckName, SourceLocation Loc, StringRef Description,
+    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
+  assert(Loc.isValid());
+  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
+      Level, (Description + " [" + CheckName + "]").str());
+  CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
+  return DiagEngine->Report(Loc, ID);
+}
+
+DiagnosticBuilder ClangTidyContext::diag(
+    StringRef CheckName, StringRef Description,
+    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
+  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
+      Level, (Description + " [" + CheckName + "]").str());
+  CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
+  return DiagEngine->Report(ID);
+}
+
+DiagnosticBuilder ClangTidyContext::diag(const ClangTidyError &Error) {
+  SourceManager &SM = DiagEngine->getSourceManager();
+  llvm::ErrorOr<const FileEntry *> File =
+      SM.getFileManager().getFile(Error.Message.FilePath);
+  FileID ID = SM.getOrCreateFileID(*File, SrcMgr::C_User);
+  SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID);
+  SourceLocation Loc = FileStartLoc.getLocWithOffset(Error.Message.FileOffset);
+  return diag(Error.DiagnosticName, Loc, Error.Message.Message,
+              static_cast<DiagnosticIDs::Level>(Error.DiagLevel));
+}
+
+DiagnosticBuilder ClangTidyContext::configurationDiag(
+    StringRef Message,
+    DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
+  return diag("clang-tidy-config", Message, Level);
+}
+
+void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
+  DiagEngine->setSourceManager(SourceMgr);
+}
+
+void ClangTidyContext::setCurrentFile(StringRef File) {
+  CurrentFile = std::string(File);
+  CurrentOptions = getOptionsForFile(CurrentFile);
+  CheckFilter = std::make_unique<CachedGlobList>(*getOptions().Checks);
+  WarningAsErrorFilter =
+      std::make_unique<CachedGlobList>(*getOptions().WarningsAsErrors);
+}
+
+void ClangTidyContext::setASTContext(ASTContext *Context) {
+  DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
+  LangOpts = Context->getLangOpts();
+}
+
+const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
+  return OptionsProvider->getGlobalOptions();
+}
+
+const ClangTidyOptions &ClangTidyContext::getOptions() const {
+  return CurrentOptions;
+}
+
+ClangTidyOptions ClangTidyContext::getOptionsForFile(StringRef File) const {
+  // Merge options on top of getDefaults() as a safeguard against options with
+  // unset values.
+  return ClangTidyOptions::getDefaults().merge(
+      OptionsProvider->getOptions(File), 0);
+}
+
+void ClangTidyContext::setEnableProfiling(bool P) { Profile = P; }
+
+void ClangTidyContext::setProfileStoragePrefix(StringRef Prefix) {
+  ProfilePrefix = std::string(Prefix);
+}
+
+llvm::Optional<ClangTidyProfiling::StorageParams>
+ClangTidyContext::getProfileStorageParams() const {
+  if (ProfilePrefix.empty())
+    return llvm::None;
+
+  return ClangTidyProfiling::StorageParams(ProfilePrefix, CurrentFile);
+}
+
+bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const {
+  assert(CheckFilter != nullptr);
+  return CheckFilter->contains(CheckName);
+}
+
+bool ClangTidyContext::treatAsError(StringRef CheckName) const {
+  assert(WarningAsErrorFilter != nullptr);
+  return WarningAsErrorFilter->contains(CheckName);
+}
+
+std::string ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
+  std::string ClangWarningOption = std::string(
+      DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
+  if (!ClangWarningOption.empty())
+    return "clang-diagnostic-" + ClangWarningOption;
+  llvm::DenseMap<unsigned, std::string>::const_iterator I =
+      CheckNamesByDiagnosticID.find(DiagnosticID);
+  if (I != CheckNamesByDiagnosticID.end())
+    return I->second;
+  return "";
+}
Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyCheck.h
+++ clang-tools-extra/clang-tidy/ClangTidyCheck.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
 
-#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyContext.h"
 #include "ClangTidyOptions.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/Diagnostic.h"
Index: clang-tools-extra/clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -17,6 +17,7 @@
 #include "ClangTidy.h"
 #include "ClangTidyCheck.h"
 #include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyError.h"
 #include "ClangTidyModuleRegistry.h"
 #include "ClangTidyProfiling.h"
 #include "ExpandModularHeadersPPCallbacks.h"
Index: clang-tools-extra/clang-tidy/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -11,6 +11,8 @@
 add_clang_library(clangTidy
   ClangTidy.cpp
   ClangTidyCheck.cpp
+  ClangTidyContext.cpp
+  ClangTidyError.cpp
   ClangTidyModule.cpp
   ClangTidyDiagnosticConsumer.cpp
   ClangTidyOptions.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to