diff clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children 0572611fdcc8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp	Thu Feb 13 15:10:13 2020 +0900
@@ -0,0 +1,294 @@
+//===- 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:
+  /// Records that a given file entry is needed for replaying callbacks.
+  void addNecessaryFile(const FileEntry *File) { FilesToRecord.insert(File); }
+
+  /// Records content for a file and adds it to the FileSystem.
+  void recordFileContent(const FileEntry *File,
+                         const SrcMgr::ContentCache &ContentCache,
+                         llvm::vfs::InMemoryFileSystem &InMemoryFs) {
+    // Return if we are not interested in the contents of this file.
+    if (!FilesToRecord.count(File))
+      return;
+
+    // FIXME: Why is this happening? We might be losing contents here.
+    if (!ContentCache.getRawBuffer())
+      return;
+
+    InMemoryFs.addFile(File->getName(), /*ModificationTime=*/0,
+                       llvm::MemoryBuffer::getMemBufferCopy(
+                           ContentCache.getRawBuffer()->getBuffer()));
+    // Remove the file from the set of necessary files.
+    FilesToRecord.erase(File);
+  }
+
+  /// Makes sure we have contents for all the files we were interested in. Ideally
+  /// `FilesToRecord` should be empty.
+  void checkAllFilesRecorded() {
+    for (auto FileEntry : FilesToRecord)
+      llvm::errs() << "Did not record contents for input file: "
+                   << FileEntry->getName() << "\n";
+  }
+
+private:
+  /// A set of files whose contents are to be recorded.
+  llvm::DenseSet<const FileEntry *> FilesToRecord;
+};
+
+ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
+    CompilerInstance *CI,
+    IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
+    : Recorder(std::make_unique<FileRecorder>()), Compiler(*CI),
+      InMemoryFs(new llvm::vfs::InMemoryFileSystem),
+      Sources(Compiler.getSourceManager()),
+      // Forward the new diagnostics to the original DiagnosticConsumer.
+      Diags(new DiagnosticIDs, new DiagnosticOptions,
+            new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
+      LangOpts(Compiler.getLangOpts()) {
+  // Add a FileSystem containing the extra files needed in place of modular
+  // headers.
+  OverlayFS->pushOverlay(InMemoryFs);
+
+  Diags.setSourceManager(&Sources);
+
+  LangOpts.Modules = false;
+
+  auto HSO = std::make_shared<HeaderSearchOptions>();
+  *HSO = Compiler.getHeaderSearchOpts();
+
+  HeaderInfo = std::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
+                                               &Compiler.getTarget());
+
+  auto PO = std::make_shared<PreprocessorOptions>();
+  *PO = Compiler.getPreprocessorOpts();
+
+  PP = std::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
+                                              *HeaderInfo, ModuleLoader,
+                                              /*IILookup=*/nullptr,
+                                              /*OwnsHeaderSearch=*/false);
+  PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
+  InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
+                         Compiler.getFrontendOpts());
+  ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
+                           Compiler.getTarget().getTriple());
+}
+
+ExpandModularHeadersPPCallbacks::~ExpandModularHeadersPPCallbacks() = default;
+
+Preprocessor *ExpandModularHeadersPPCallbacks::getPreprocessor() const {
+  return PP.get();
+}
+
+void ExpandModularHeadersPPCallbacks::handleModuleFile(
+    serialization::ModuleFile *MF) {
+  if (!MF)
+    return;
+  // Avoid processing a ModuleFile more than once.
+  if (VisitedModules.count(MF))
+    return;
+  VisitedModules.insert(MF);
+
+  // Visit all the input files of this module and mark them to record their
+  // contents later.
+  Compiler.getASTReader()->visitInputFiles(
+      *MF, true, false,
+      [this](const serialization::InputFile &IF, bool /*IsSystem*/) {
+        Recorder->addNecessaryFile(IF.getFile());
+      });
+  // 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) {
+    Recorder->recordFileContent(It->getFirst(), *It->getSecond(), *InMemoryFs);
+  }
+  Recorder->checkAllFilesRecorded();
+
+  if (!StartedLexing) {
+    StartedLexing = true;
+    PP->Lex(CurrentToken);
+  }
+  while (!CurrentToken.is(tok::eof) &&
+         Sources.isBeforeInTranslationUnit(CurrentToken.getLocation(), Loc)) {
+    PP->Lex(CurrentToken);
+  }
+}
+
+void ExpandModularHeadersPPCallbacks::FileChanged(
+    SourceLocation Loc, FileChangeReason Reason,
+    SrcMgr::CharacteristicKind FileType, FileID PrevFID = FileID()) {
+  if (!EnteredMainFile) {
+    EnteredMainFile = true;
+    PP->EnterMainSourceFile();
+  }
+}
+
+void ExpandModularHeadersPPCallbacks::InclusionDirective(
+    SourceLocation DirectiveLoc, const Token &IncludeToken,
+    StringRef IncludedFilename, bool IsAngled, CharSourceRange FilenameRange,
+    const FileEntry *IncludedFile, StringRef SearchPath, StringRef RelativePath,
+    const Module *Imported, SrcMgr::CharacteristicKind FileType) {
+  if (Imported) {
+    serialization::ModuleFile *MF =
+        Compiler.getASTReader()->getModuleManager().lookup(
+            Imported->getASTFile());
+    handleModuleFile(MF);
+  }
+  parseToLocation(DirectiveLoc);
+}
+
+void ExpandModularHeadersPPCallbacks::EndOfMainFile() {
+  while (!CurrentToken.is(tok::eof))
+    PP->Lex(CurrentToken);
+}
+
+// Handle all other callbacks.
+// Just parse to the corresponding location to generate the same callback for
+// the PPCallbacks registered in our custom preprocessor.
+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, Optional<FileEntryRef>,
+                                                 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