forked from OSchip/llvm-project
308 lines
12 KiB
C++
308 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"
|
|
|
|
#define DEBUG_TYPE "clang-tidy"
|
|
|
|
namespace clang {
|
|
namespace 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.
|
|
llvm::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,
|
|
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
|