forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			297 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- 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/Basic/FileManager.h"
 | 
						|
#include "clang/Basic/TargetInfo.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
 |