123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- //===- 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"
- #include <optional>
- #define DEBUG_TYPE "clang-tidy"
- namespace clang::tooling {
- class ExpandModularHeadersPPCallbacks::FileRecorder {
- public:
- /// Records that a given file entry is needed for replaying callbacks.
- void addNecessaryFile(const FileEntry *File) {
- // Don't record modulemap files because it breaks same file detection.
- if (!(File->getName().endswith("module.modulemap") ||
- File->getName().endswith("module.private.modulemap") ||
- File->getName().endswith("module.map") ||
- File->getName().endswith("module_private.map")))
- 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.
- std::optional<StringRef> Data = ContentCache.getBufferDataIfLoaded();
- if (!Data)
- return;
- InMemoryFs.addFile(File->getName(), /*ModificationTime=*/0,
- llvm::MemoryBuffer::getMemBufferCopy(*Data));
- // 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() {
- LLVM_DEBUG({
- for (auto FileEntry : FilesToRecord)
- llvm::dbgs() << "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,
- OptionalFileEntryRef 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, OptionalFileEntryRef,
- SrcMgr::CharacteristicKind) {
- parseToLocation(Loc);
- }
- void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
- SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
- unsigned) {
- // FIXME: Figure out whether it's the right location to parse to.
- parseToLocation(NameLoc);
- }
- void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
- PragmaWarningSpecifier,
- 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 *) {
- // FIXME: 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) {
- // FIXME: Figure out whether it's the right location to parse to.
- parseToLocation(Range.getBegin());
- }
- void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
- SourceRange Range, SourceLocation EndifLoc) {
- // FIXME: 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 clang::tooling
|