alexfh updated this revision to Diff 191227.
alexfh added a comment.

- Fix a typo in the comment. Rearrange paragraphs to make the comment more 
readable.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59528/new/

https://reviews.llvm.org/D59528

Files:
  clang-tools-extra/clang-tidy/CMakeLists.txt
  clang-tools-extra/clang-tidy/ClangTidy.cpp
  clang-tools-extra/clang-tidy/ClangTidy.h
  clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
  clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
  clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
  clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
  clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
  clang-tools-extra/test/CMakeLists.txt
  
clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/a.h
  
clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/b.h
  
clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/c.h
  
clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/module.modulemap
  clang-tools-extra/test/clang-tidy/expand-modular-headers-ppcallbacks.cpp

Index: clang-tools-extra/test/clang-tidy/expand-modular-headers-ppcallbacks.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/expand-modular-headers-ppcallbacks.cpp
@@ -0,0 +1,31 @@
+// Sanity-check. Run without modules:
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: cp %S/Inputs/expand-modular-headers-ppcallbacks/* %t/
+// RUN: %check_clang_tidy %s readability-identifier-naming %t/without-modules -- \
+// RUN:   -config="CheckOptions: [{ \
+// RUN:      key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }]" \
+// RUN:   -header-filter=.* \
+// RUN:   -- -x c++ -std=c++11 -I%t/
+//
+// Run clang-tidy on a file with modular includes:
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: cp %S/Inputs/expand-modular-headers-ppcallbacks/* %t/
+// RUN: %check_clang_tidy %s readability-identifier-naming %t/with-modules -- \
+// RUN:   -config="CheckOptions: [{ \
+// RUN:      key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }]" \
+// RUN:   -header-filter=.* \
+// RUN:   -- -x c++ -std=c++11 -I%t/ \
+// RUN:   -fmodules -fimplicit-modules -fno-implicit-module-maps \
+// RUN:   -fmodule-map-file=%t/module.modulemap \
+// RUN:   -fmodules-cache-path=%t/module-cache/
+#include "c.h"
+
+// CHECK-MESSAGES: a.h:1:9: warning: invalid case style for macro definition 'a' [readability-identifier-naming]
+// CHECK-MESSAGES: a.h:1:9: note: FIX-IT applied suggested code changes
+// CHECK-MESSAGES: b.h:2:9: warning: invalid case style for macro definition 'b' [readability-identifier-naming]
+// CHECK-MESSAGES: b.h:2:9: note: FIX-IT applied suggested code changes
+// CHECK-MESSAGES: c.h:2:9: warning: invalid case style for macro definition 'c' [readability-identifier-naming]
+// CHECK-MESSAGES: c.h:2:9: note: FIX-IT applied suggested code changes
Index: clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/module.modulemap
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/module.modulemap
@@ -0,0 +1,3 @@
+module a { header "a.h" export * }
+module b { header "b.h" export * use a }
+module c { header "c.h" export * use b }
Index: clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/c.h
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/c.h
@@ -0,0 +1,2 @@
+#include "b.h"
+#define c
Index: clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/b.h
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/b.h
@@ -0,0 +1,2 @@
+#include "a.h"
+#define b
Index: clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/a.h
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/Inputs/expand-modular-headers-ppcallbacks/a.h
@@ -0,0 +1 @@
+#define a
Index: clang-tools-extra/test/CMakeLists.txt
===================================================================
--- clang-tools-extra/test/CMakeLists.txt
+++ clang-tools-extra/test/CMakeLists.txt
@@ -62,6 +62,8 @@
   clang-resource-headers
 
   clang-tidy
+  # Clang-tidy tests need clang for building modules.
+  clang
 )
 
 if(CLANGD_BUILD_XPC_SUPPORT)
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
@@ -304,11 +304,10 @@
 }
 
 llvm::IntrusiveRefCntPtr<vfs::FileSystem>
-getVfsOverlayFromFile(const std::string &OverlayFile) {
-  llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFS(
-      new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+getVfsFromFile(const std::string &OverlayFile,
+               llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
-      OverlayFS->getBufferForFile(OverlayFile);
+      BaseFS->getBufferForFile(OverlayFile);
   if (!Buffer) {
     llvm::errs() << "Can't load virtual filesystem overlay file '"
                  << OverlayFile << "': " << Buffer.getError().message()
@@ -323,19 +322,23 @@
                  << OverlayFile << "'.\n";
     return nullptr;
   }
-  OverlayFS->pushOverlay(FS);
-  return OverlayFS;
+  return FS;
 }
 
 static int clangTidyMain(int argc, const char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory,
                                     cl::ZeroOrMore);
-  llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS(
-      VfsOverlay.empty() ? vfs::getRealFileSystem()
-                         : getVfsOverlayFromFile(VfsOverlay));
-  if (!BaseFS)
-    return 1;
+  llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS(
+      new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+
+  if (!VfsOverlay.empty()) {
+    IntrusiveRefCntPtr<vfs::FileSystem> VfsFromFile =
+        getVfsFromFile(VfsOverlay, BaseFS);
+    if (!VfsFromFile)
+      return 1;
+    BaseFS->pushOverlay(VfsFromFile);
+  }
 
   auto OwningOptionsProvider = createOptionsProvider(BaseFS);
   auto *OptionsProvider = OwningOptionsProvider.get();
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -38,7 +38,8 @@
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-  void registerPPCallbacks(CompilerInstance &Compiler) override;
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override;
   void onEndOfTranslationUnit() override;
 
   enum CaseType {
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -240,10 +240,11 @@
   Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
 }
 
-void IdentifierNamingCheck::registerPPCallbacks(CompilerInstance &Compiler) {
-  Compiler.getPreprocessor().addPPCallbacks(
-      llvm::make_unique<IdentifierNamingCheckPPCallbacks>(
-          &Compiler.getPreprocessor(), this));
+void IdentifierNamingCheck::registerPPCallbacks(
+    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+  ModuleExpanderPP->addPPCallbacks(
+      llvm::make_unique<IdentifierNamingCheckPPCallbacks>(ModuleExpanderPP,
+                                                          this));
 }
 
 static bool matchesStyle(StringRef Name,
Index: clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -0,0 +1,135 @@
+//===- ExpandModularHeadersPPCallbacks.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the ExpandModularHeadersPPCallbacks class that handles #includes of
+// modular headers, traverses all transitively included headers in non-modular
+// mode and generates PPCallbacks for their contents.
+// This allows existing tools based on PPCallbacks to retain their functionality
+// when running with C++ modules enabled.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_EXPANDMODULARHEADERSPPCALLBACKS_H_
+#define LLVM_CLANG_TOOLING_EXPANDMODULARHEADERSPPCALLBACKS_H_
+
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace clang {
+class CompilerInstance;
+
+namespace serialization {
+class ModuleFile;
+}
+
+namespace tooling {
+
+/// \brief Handles PPCallbacks and replays preprocessing with modules disabled.
+///
+/// This way it's possible to get PPCallbacks from the contents of the modular
+/// headers and all their transitive includes.
+class ExpandModularHeadersPPCallbacks : public PPCallbacks {
+public:
+  ExpandModularHeadersPPCallbacks(
+      CompilerInstance *compiler,
+      IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS);
+  ~ExpandModularHeadersPPCallbacks();
+
+  /// \brief Users can get expanded PPCallbacks by registering their callback
+  /// handlers in the preprocessor instance returned by this method.
+  Preprocessor *getPreprocessor() const;
+
+private:
+  class FileRecorder;
+
+  void handleModuleFile(serialization::ModuleFile *MF);
+  void ParseToLocation(SourceLocation loc);
+
+  // Handle PPCallbacks.
+  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                   SrcMgr::CharacteristicKind FileType,
+                   FileID PrevFID) override;
+
+  void InclusionDirective(SourceLocation directive_loc,
+                          const Token &include_token,
+                          StringRef included_filename, bool is_angled,
+                          CharSourceRange filename_range,
+                          const FileEntry *included_file, StringRef search_path,
+                          StringRef relative_path, const Module *imported,
+                          SrcMgr::CharacteristicKind FileType) override;
+
+  // FIXME: This crashes:
+  // void EndOfMainFile() override { target_callbacks_->EndOfMainFile(); }
+
+  // Handle all other callbacks.
+  // Just parse to the corresponding location to generate PPCallbacks for the
+  // corresponding range
+  void Ident(SourceLocation Loc, StringRef) override;
+  void PragmaDirective(SourceLocation Loc, PragmaIntroducerKind) override;
+  void PragmaComment(SourceLocation Loc, const IdentifierInfo *,
+                     StringRef) override;
+  void PragmaDetectMismatch(SourceLocation Loc, StringRef, StringRef) override;
+  void PragmaDebug(SourceLocation Loc, StringRef) override;
+  void PragmaMessage(SourceLocation Loc, StringRef, PragmaMessageKind,
+                     StringRef) override;
+  void PragmaDiagnosticPush(SourceLocation Loc, StringRef) override;
+  void PragmaDiagnosticPop(SourceLocation Loc, StringRef) override;
+  void PragmaDiagnostic(SourceLocation Loc, StringRef, diag::Severity,
+                        StringRef) override;
+  void HasInclude(SourceLocation Loc, StringRef, bool, const FileEntry *,
+                  SrcMgr::CharacteristicKind) override;
+  void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *,
+                             SourceLocation StateLoc, unsigned) override;
+  void PragmaWarning(SourceLocation Loc, StringRef, ArrayRef<int>) override;
+  void PragmaWarningPush(SourceLocation Loc, int) override;
+  void PragmaWarningPop(SourceLocation Loc) override;
+  void PragmaAssumeNonNullBegin(SourceLocation Loc) override;
+  void PragmaAssumeNonNullEnd(SourceLocation Loc) override;
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &,
+                    SourceRange Range, const MacroArgs *) override;
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override;
+  void MacroUndefined(const Token &, const MacroDefinition &,
+                      const MacroDirective *Undef) override;
+  void Defined(const Token &MacroNameTok, const MacroDefinition &,
+               SourceRange Range) override;
+  void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override;
+  void If(SourceLocation Loc, SourceRange, ConditionValueKind) override;
+  void Elif(SourceLocation Loc, SourceRange, ConditionValueKind,
+            SourceLocation) override;
+  void Ifdef(SourceLocation Loc, const Token &,
+             const MacroDefinition &) override;
+  void Ifndef(SourceLocation Loc, const Token &,
+              const MacroDefinition &) override;
+  void Else(SourceLocation Loc, SourceLocation) override;
+  void Endif(SourceLocation Loc, SourceLocation) override;
+
+  std::unique_ptr<FileRecorder> file_recorder_;
+  // Set of all the modules visited. Avoids processing a module more than once.
+  llvm::DenseSet<serialization::ModuleFile *> visited_modules_;
+
+  CompilerInstance &compiler_;
+  // Additional filesystem for replay. Provides all input files from modules.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> in_memory_fs_;
+
+  SourceManager &sources_;
+  DiagnosticsEngine diags_;
+  LangOptions lang_opts_;
+  TrivialModuleLoader module_loader_;
+
+  std::unique_ptr<HeaderSearch> header_info_;
+  std::unique_ptr<Preprocessor> preprocessor_;
+  bool entered_main_file_ = false;
+  bool started_lexing_ = false;
+  Token current_token_;
+};
+
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLING_EXPANDMODULARHEADERSPPCALLBACKS_H_
Index: clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -0,0 +1,302 @@
+//===- ExpandModularHeadersPPCallbacks.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExpandModularHeadersPPCallbacks.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Serialization/ASTReader.h"
+
+namespace clang {
+namespace tooling {
+
+class ExpandModularHeadersPPCallbacks::FileRecorder {
+public:
+  // Stores FileEntry for which contents are to be recorded later.
+  void AddFileToRecord(const FileEntry *file) { files_to_record_.insert(file); }
+
+  // Records content for a file and adds it to the FileSystem.
+  void RecordContent(const FileEntry *file,
+                     const SrcMgr::ContentCache *content_cache,
+                     llvm::vfs::InMemoryFileSystem &in_memory_fs_) {
+    // Return if we are not interested in the contents of this file.
+    if (!files_to_record_.count(file))
+      return;
+
+    //assert(content_cache->getRawBuffer() && "No raw buffer");
+    // FIXME: Why is this happening? We might be losing contents here.
+    if (!content_cache->getRawBuffer())
+      return;
+
+    in_memory_fs_.addFile(file->getName(), /*ModificationTime=*/0,
+                          llvm::MemoryBuffer::getMemBufferCopy(
+                              content_cache->getRawBuffer()->getBuffer()));
+    // Remove file since we have successfully recorded its contents.
+    files_to_record_.erase(file);
+  }
+
+  // Make sure we have contents for all the files we were interested in. Ideally
+  // `files_to_record_` should be empty.
+  void CheckAllFilesRecorded() {
+    for (auto file_entry : files_to_record_)
+      llvm::errs() << "Did not record contents for input file: "
+                   << file_entry->getName() << "\n";
+  }
+
+private:
+  // Set of files whose contents are to be recorded.
+  llvm::DenseSet<const FileEntry *> files_to_record_;
+};
+
+ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
+    CompilerInstance *compiler,
+    IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
+    : file_recorder_(llvm::make_unique<FileRecorder>()), compiler_(*compiler),
+      in_memory_fs_(new llvm::vfs::InMemoryFileSystem),
+      sources_(compiler_.getSourceManager()),
+      // Forward the new diagnostics to the original DiagnosticConsumer.
+      diags_(new DiagnosticIDs, new DiagnosticOptions,
+             new ForwardingDiagnosticConsumer(compiler_.getDiagnosticClient())),
+      lang_opts_(compiler_.getLangOpts()) {
+  // Add FileSystem containing the extra files needed in place of modular
+  // headers.
+  OverlayFS->pushOverlay(in_memory_fs_);
+
+  diags_.setSourceManager(&sources_);
+
+  // Switch of header modules in the new preprocessor.
+  lang_opts_.Modules = false;
+
+  auto header_search_options = std::make_shared<HeaderSearchOptions>();
+  *header_search_options = compiler_.getHeaderSearchOpts();
+
+  header_info_ =
+      llvm::make_unique<HeaderSearch>(header_search_options, sources_, diags_,
+                                      lang_opts_, &compiler_.getTarget());
+
+  auto preprocessor_options = std::make_shared<PreprocessorOptions>();
+  *preprocessor_options = compiler_.getPreprocessorOpts();
+
+  preprocessor_ =
+      llvm::make_unique<Preprocessor>(preprocessor_options, diags_, lang_opts_,
+                                      sources_, *header_info_, module_loader_,
+                                      /*IILookup=*/nullptr,
+                                      /*OwnsHeaderSearch=*/false);
+  preprocessor_->Initialize(compiler_.getTarget(), compiler_.getAuxTarget());
+  InitializePreprocessor(*preprocessor_, *preprocessor_options,
+                         compiler_.getPCHContainerReader(),
+                         compiler_.getFrontendOpts());
+  ApplyHeaderSearchOptions(*header_info_, *header_search_options, lang_opts_,
+                           compiler_.getTarget().getTriple());
+}
+
+ExpandModularHeadersPPCallbacks::~ExpandModularHeadersPPCallbacks() = default;
+
+Preprocessor *ExpandModularHeadersPPCallbacks::getPreprocessor() const {
+  return preprocessor_.get();
+}
+
+void ExpandModularHeadersPPCallbacks::handleModuleFile(
+    serialization::ModuleFile *MF) {
+  if (!MF)
+    return;
+  // Avoid processing a ModuleFile more than once.
+  if (visited_modules_.count(MF))
+    return;
+  visited_modules_.insert(MF);
+
+  // Visit all the input files of this module and mark them to be record their
+  // contents later.
+  compiler_.getModuleManager()->visitInputFiles(
+      *MF, true, false,
+      [this](const serialization::InputFile &IF, bool isSystem) {
+        auto *F = IF.getFile();
+        file_recorder_->AddFileToRecord(F);
+      });
+  // Recursively handle all transitively imported modules.
+  for (auto import : MF->Imports)
+    handleModuleFile(import);
+}
+
+void ExpandModularHeadersPPCallbacks::ParseToLocation(SourceLocation loc) {
+  // Load all source locations present in the external sources.
+  for (unsigned I = 0, N = sources_.loaded_sloc_entry_size(); I != N; ++I) {
+    sources_.getLoadedSLocEntry(I, nullptr);
+  }
+  // Record contents of files we are interested in and add to the FileSystem.
+  for (auto it = sources_.fileinfo_begin(); it != sources_.fileinfo_end();
+       ++it) {
+    file_recorder_->RecordContent(it->getFirst(), it->getSecond(),
+                                  *in_memory_fs_);
+  }
+  file_recorder_->CheckAllFilesRecorded();
+
+  if (!started_lexing_) {
+    started_lexing_ = true;
+    preprocessor_->Lex(current_token_);
+  }
+  while (
+      !current_token_.is(tok::eof) &&
+      sources_.isBeforeInTranslationUnit(current_token_.getLocation(), loc)) {
+    preprocessor_->Lex(current_token_);
+  }
+}
+
+void ExpandModularHeadersPPCallbacks::FileChanged(
+    SourceLocation Loc, FileChangeReason Reason,
+    SrcMgr::CharacteristicKind FileType, FileID PrevFID = FileID()) {
+  if (!entered_main_file_) {
+    entered_main_file_ = true;
+    preprocessor_->EnterMainSourceFile();
+  }
+}
+
+void ExpandModularHeadersPPCallbacks::InclusionDirective(
+    SourceLocation directive_loc, const Token &include_token,
+    StringRef included_filename, bool is_angled, CharSourceRange filename_range,
+    const FileEntry *included_file, StringRef search_path,
+    StringRef relative_path, const Module *imported,
+    SrcMgr::CharacteristicKind FileType) {
+  if (imported) {
+    serialization::ModuleFile *MF =
+        compiler_.getModuleManager()->getModuleManager().lookup(
+            imported->getASTFile());
+    handleModuleFile(MF);
+  }
+  ParseToLocation(directive_loc);
+}
+
+// FIXME: This crashes: void EndOfMainFile() override {
+// target_callbacks_->EndOfMainFile(); }
+
+// Handle all other callbacks.
+// Just parse to the corresponding location to generate the same callback for
+// the target_callbacks_.
+void ExpandModularHeadersPPCallbacks::Ident(SourceLocation Loc, StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDirective(SourceLocation Loc,
+                                                      PragmaIntroducerKind) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaComment(SourceLocation Loc,
+                                                    const IdentifierInfo *,
+                                                    StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
+                                                           StringRef,
+                                                           StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDebug(SourceLocation Loc,
+                                                  StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaMessage(SourceLocation Loc,
+                                                    StringRef,
+                                                    PragmaMessageKind,
+                                                    StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPush(SourceLocation Loc,
+                                                           StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPop(SourceLocation Loc,
+                                                          StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
+                                                       StringRef,
+                                                       diag::Severity,
+                                                       StringRef) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc, StringRef,
+                                                 bool, const FileEntry *,
+                                                 SrcMgr::CharacteristicKind) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
+    SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
+    unsigned) {
+  // FIME: Figure out whether it's the right location to parse to.
+  ParseToLocation(NameLoc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
+                                                    StringRef, ArrayRef<int>) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaWarningPush(SourceLocation Loc,
+                                                        int) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullBegin(
+    SourceLocation Loc) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullEnd(
+    SourceLocation Loc) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok,
+                                                   const MacroDefinition &,
+                                                   SourceRange Range,
+                                                   const MacroArgs *) {
+  // FIME: Figure out whether it's the right location to parse to.
+  ParseToLocation(Range.getBegin());
+}
+void ExpandModularHeadersPPCallbacks::MacroDefined(const Token &MacroNameTok,
+                                                   const MacroDirective *MD) {
+  ParseToLocation(MD->getLocation());
+}
+void ExpandModularHeadersPPCallbacks::MacroUndefined(
+    const Token &, const MacroDefinition &, const MacroDirective *Undef) {
+  if (Undef)
+    ParseToLocation(Undef->getLocation());
+}
+void ExpandModularHeadersPPCallbacks::Defined(const Token &MacroNameTok,
+                                              const MacroDefinition &,
+                                              SourceRange Range) {
+  // FIME: Figure out whether it's the right location to parse to.
+  ParseToLocation(Range.getBegin());
+}
+void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
+    SourceRange Range, SourceLocation EndifLoc) {
+  // FIME: Figure out whether it's the right location to parse to.
+  ParseToLocation(EndifLoc);
+}
+void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc, SourceRange,
+                                         ConditionValueKind) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::Elif(SourceLocation Loc, SourceRange,
+                                           ConditionValueKind, SourceLocation) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::Ifdef(SourceLocation Loc, const Token &,
+                                            const MacroDefinition &) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::Ifndef(SourceLocation Loc, const Token &,
+                                             const MacroDefinition &) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::Else(SourceLocation Loc, SourceLocation) {
+  ParseToLocation(Loc);
+}
+void ExpandModularHeadersPPCallbacks::Endif(SourceLocation Loc,
+                                            SourceLocation) {
+  ParseToLocation(Loc);
+}
+
+} // namespace tooling
+} // namespace clang
Index: clang-tools-extra/clang-tidy/ClangTidy.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.h
+++ clang-tools-extra/clang-tidy/ClangTidy.h
@@ -143,6 +143,18 @@
   /// dependent properties, e.g. the order of include directives.
   virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
 
+  /// \brief Override this to register ``PPCallbacks`` in the preprocessor.
+  ///
+  /// This should be used for clang-tidy checks that analyze preprocessor-
+  /// dependent properties, e.g. include directives and macro definitions.
+  ///
+  /// There are two Preprocessors to choose from: the real one and the one that
+  /// generates callbacks for all transitively included headers even when
+  /// compiling with modules. When compiling without modules, both pointers
+  /// point to the real preprocessor.
+  virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                                   Preprocessor *ModuleExpanderPP) {}
+
   /// \brief Override this to register AST matchers with \p Finder.
   ///
   /// This should be used by clang-tidy checks that analyze code properties that
@@ -190,7 +202,9 @@
 
 class ClangTidyASTConsumerFactory {
 public:
-  ClangTidyASTConsumerFactory(ClangTidyContext &Context);
+  ClangTidyASTConsumerFactory(
+      ClangTidyContext &Context,
+      IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS = nullptr);
 
   /// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
   std::unique_ptr<clang::ASTConsumer>
@@ -204,6 +218,7 @@
 
 private:
   ClangTidyContext &Context;
+  IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;
   std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
 };
 
@@ -233,7 +248,7 @@
 runClangTidy(clang::tidy::ClangTidyContext &Context,
              const tooling::CompilationDatabase &Compilations,
              ArrayRef<std::string> InputFiles,
-             llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+             llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
              bool EnableCheckProfile = false,
              llvm::StringRef StoreCheckProfile = StringRef());
 
Index: clang-tools-extra/clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -18,6 +18,7 @@
 #include "ClangTidyDiagnosticConsumer.h"
 #include "ClangTidyModuleRegistry.h"
 #include "ClangTidyProfiling.h"
+#include "ExpandModularHeadersPPCallbacks.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
@@ -290,8 +291,10 @@
 } // namespace
 
 ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
-    ClangTidyContext &Context)
-    : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
+    ClangTidyContext &Context,
+    IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
+    : Context(Context), OverlayFS(OverlayFS),
+      CheckFactories(new ClangTidyCheckFactories) {
   for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
                                          E = ClangTidyModuleRegistry::end();
        I != E; ++I) {
@@ -351,7 +354,8 @@
     clang::CompilerInstance &Compiler, StringRef File) {
   // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
   // modify Compiler.
-  Context.setSourceManager(&Compiler.getSourceManager());
+  SourceManager *SM = &Compiler.getSourceManager();
+  Context.setSourceManager(SM);
   Context.setCurrentFile(File);
   Context.setASTContext(&Compiler.getASTContext());
 
@@ -377,9 +381,20 @@
   std::unique_ptr<ast_matchers::MatchFinder> Finder(
       new ast_matchers::MatchFinder(std::move(FinderOptions)));
 
+  Preprocessor *PP = &Compiler.getPreprocessor();
+  Preprocessor *ModuleExpanderPP = PP;
+
+  if (Context.getLangOpts().Modules && OverlayFS != nullptr) {
+    auto ModuleExpander = llvm::make_unique<ExpandModularHeadersPPCallbacks>(
+        &Compiler, OverlayFS);
+    ModuleExpanderPP = ModuleExpander->getPreprocessor();
+    PP->addPPCallbacks(std::move(ModuleExpander));
+  }
+
   for (auto &Check : Checks) {
     Check->registerMatchers(&*Finder);
     Check->registerPPCallbacks(Compiler);
+    Check->registerPPCallbacks(*SM, PP, ModuleExpanderPP);
   }
 
   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
@@ -505,7 +520,7 @@
 runClangTidy(clang::tidy::ClangTidyContext &Context,
              const CompilationDatabase &Compilations,
              ArrayRef<std::string> InputFiles,
-             llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+             llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
              bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) {
   ClangTool Tool(Compilations, InputFiles,
                  std::make_shared<PCHContainerOperations>(), BaseFS);
@@ -541,7 +556,9 @@
 
   class ActionFactory : public FrontendActionFactory {
   public:
-    ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
+    ActionFactory(ClangTidyContext &Context,
+                  IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS)
+        : ConsumerFactory(Context, BaseFS) {}
     FrontendAction *create() override { return new Action(&ConsumerFactory); }
 
     bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
@@ -572,7 +589,7 @@
     ClangTidyASTConsumerFactory ConsumerFactory;
   };
 
-  ActionFactory Factory(Context);
+  ActionFactory Factory(Context, BaseFS);
   Tool.run(&Factory);
   return DiagConsumer.take();
 }
Index: clang-tools-extra/clang-tidy/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -8,6 +8,7 @@
   ClangTidyDiagnosticConsumer.cpp
   ClangTidyOptions.cpp
   ClangTidyProfiling.cpp
+  ExpandModularHeadersPPCallbacks.cpp
 
   DEPENDS
   ClangSACheckers
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to