ExpandModularHeadersPPCallbacks.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. //===- ExpandModularHeadersPPCallbacks.h - clang-tidy -----------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "ExpandModularHeadersPPCallbacks.h"
  9. #include "clang/Basic/FileManager.h"
  10. #include "clang/Basic/TargetInfo.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Lex/PreprocessorOptions.h"
  13. #include "clang/Serialization/ASTReader.h"
  14. #include <optional>
  15. #define DEBUG_TYPE "clang-tidy"
  16. namespace clang::tooling {
  17. class ExpandModularHeadersPPCallbacks::FileRecorder {
  18. public:
  19. /// Records that a given file entry is needed for replaying callbacks.
  20. void addNecessaryFile(const FileEntry *File) {
  21. // Don't record modulemap files because it breaks same file detection.
  22. if (!(File->getName().endswith("module.modulemap") ||
  23. File->getName().endswith("module.private.modulemap") ||
  24. File->getName().endswith("module.map") ||
  25. File->getName().endswith("module_private.map")))
  26. FilesToRecord.insert(File);
  27. }
  28. /// Records content for a file and adds it to the FileSystem.
  29. void recordFileContent(const FileEntry *File,
  30. const SrcMgr::ContentCache &ContentCache,
  31. llvm::vfs::InMemoryFileSystem &InMemoryFs) {
  32. // Return if we are not interested in the contents of this file.
  33. if (!FilesToRecord.count(File))
  34. return;
  35. // FIXME: Why is this happening? We might be losing contents here.
  36. std::optional<StringRef> Data = ContentCache.getBufferDataIfLoaded();
  37. if (!Data)
  38. return;
  39. InMemoryFs.addFile(File->getName(), /*ModificationTime=*/0,
  40. llvm::MemoryBuffer::getMemBufferCopy(*Data));
  41. // Remove the file from the set of necessary files.
  42. FilesToRecord.erase(File);
  43. }
  44. /// Makes sure we have contents for all the files we were interested in. Ideally
  45. /// `FilesToRecord` should be empty.
  46. void checkAllFilesRecorded() {
  47. LLVM_DEBUG({
  48. for (auto FileEntry : FilesToRecord)
  49. llvm::dbgs() << "Did not record contents for input file: "
  50. << FileEntry->getName() << "\n";
  51. });
  52. }
  53. private:
  54. /// A set of files whose contents are to be recorded.
  55. llvm::DenseSet<const FileEntry *> FilesToRecord;
  56. };
  57. ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
  58. CompilerInstance *CI,
  59. IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
  60. : Recorder(std::make_unique<FileRecorder>()), Compiler(*CI),
  61. InMemoryFs(new llvm::vfs::InMemoryFileSystem),
  62. Sources(Compiler.getSourceManager()),
  63. // Forward the new diagnostics to the original DiagnosticConsumer.
  64. Diags(new DiagnosticIDs, new DiagnosticOptions,
  65. new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
  66. LangOpts(Compiler.getLangOpts()) {
  67. // Add a FileSystem containing the extra files needed in place of modular
  68. // headers.
  69. OverlayFS->pushOverlay(InMemoryFs);
  70. Diags.setSourceManager(&Sources);
  71. LangOpts.Modules = false;
  72. auto HSO = std::make_shared<HeaderSearchOptions>();
  73. *HSO = Compiler.getHeaderSearchOpts();
  74. HeaderInfo = std::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
  75. &Compiler.getTarget());
  76. auto PO = std::make_shared<PreprocessorOptions>();
  77. *PO = Compiler.getPreprocessorOpts();
  78. PP = std::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
  79. *HeaderInfo, ModuleLoader,
  80. /*IILookup=*/nullptr,
  81. /*OwnsHeaderSearch=*/false);
  82. PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
  83. InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
  84. Compiler.getFrontendOpts());
  85. ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
  86. Compiler.getTarget().getTriple());
  87. }
  88. ExpandModularHeadersPPCallbacks::~ExpandModularHeadersPPCallbacks() = default;
  89. Preprocessor *ExpandModularHeadersPPCallbacks::getPreprocessor() const {
  90. return PP.get();
  91. }
  92. void ExpandModularHeadersPPCallbacks::handleModuleFile(
  93. serialization::ModuleFile *MF) {
  94. if (!MF)
  95. return;
  96. // Avoid processing a ModuleFile more than once.
  97. if (VisitedModules.count(MF))
  98. return;
  99. VisitedModules.insert(MF);
  100. // Visit all the input files of this module and mark them to record their
  101. // contents later.
  102. Compiler.getASTReader()->visitInputFiles(
  103. *MF, true, false,
  104. [this](const serialization::InputFile &IF, bool /*IsSystem*/) {
  105. Recorder->addNecessaryFile(IF.getFile());
  106. });
  107. // Recursively handle all transitively imported modules.
  108. for (auto *Import : MF->Imports)
  109. handleModuleFile(Import);
  110. }
  111. void ExpandModularHeadersPPCallbacks::parseToLocation(SourceLocation Loc) {
  112. // Load all source locations present in the external sources.
  113. for (unsigned I = 0, N = Sources.loaded_sloc_entry_size(); I != N; ++I) {
  114. Sources.getLoadedSLocEntry(I, nullptr);
  115. }
  116. // Record contents of files we are interested in and add to the FileSystem.
  117. for (auto It = Sources.fileinfo_begin(); It != Sources.fileinfo_end(); ++It) {
  118. Recorder->recordFileContent(It->getFirst(), *It->getSecond(), *InMemoryFs);
  119. }
  120. Recorder->checkAllFilesRecorded();
  121. if (!StartedLexing) {
  122. StartedLexing = true;
  123. PP->Lex(CurrentToken);
  124. }
  125. while (!CurrentToken.is(tok::eof) &&
  126. Sources.isBeforeInTranslationUnit(CurrentToken.getLocation(), Loc)) {
  127. PP->Lex(CurrentToken);
  128. }
  129. }
  130. void ExpandModularHeadersPPCallbacks::FileChanged(
  131. SourceLocation Loc, FileChangeReason Reason,
  132. SrcMgr::CharacteristicKind FileType, FileID PrevFID = FileID()) {
  133. if (!EnteredMainFile) {
  134. EnteredMainFile = true;
  135. PP->EnterMainSourceFile();
  136. }
  137. }
  138. void ExpandModularHeadersPPCallbacks::InclusionDirective(
  139. SourceLocation DirectiveLoc, const Token &IncludeToken,
  140. StringRef IncludedFilename, bool IsAngled, CharSourceRange FilenameRange,
  141. OptionalFileEntryRef IncludedFile, StringRef SearchPath,
  142. StringRef RelativePath, const Module *Imported,
  143. SrcMgr::CharacteristicKind FileType) {
  144. if (Imported) {
  145. serialization::ModuleFile *MF =
  146. Compiler.getASTReader()->getModuleManager().lookup(
  147. Imported->getASTFile());
  148. handleModuleFile(MF);
  149. }
  150. parseToLocation(DirectiveLoc);
  151. }
  152. void ExpandModularHeadersPPCallbacks::EndOfMainFile() {
  153. while (!CurrentToken.is(tok::eof))
  154. PP->Lex(CurrentToken);
  155. }
  156. // Handle all other callbacks.
  157. // Just parse to the corresponding location to generate the same callback for
  158. // the PPCallbacks registered in our custom preprocessor.
  159. void ExpandModularHeadersPPCallbacks::Ident(SourceLocation Loc, StringRef) {
  160. parseToLocation(Loc);
  161. }
  162. void ExpandModularHeadersPPCallbacks::PragmaDirective(SourceLocation Loc,
  163. PragmaIntroducerKind) {
  164. parseToLocation(Loc);
  165. }
  166. void ExpandModularHeadersPPCallbacks::PragmaComment(SourceLocation Loc,
  167. const IdentifierInfo *,
  168. StringRef) {
  169. parseToLocation(Loc);
  170. }
  171. void ExpandModularHeadersPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
  172. StringRef,
  173. StringRef) {
  174. parseToLocation(Loc);
  175. }
  176. void ExpandModularHeadersPPCallbacks::PragmaDebug(SourceLocation Loc,
  177. StringRef) {
  178. parseToLocation(Loc);
  179. }
  180. void ExpandModularHeadersPPCallbacks::PragmaMessage(SourceLocation Loc,
  181. StringRef,
  182. PragmaMessageKind,
  183. StringRef) {
  184. parseToLocation(Loc);
  185. }
  186. void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPush(SourceLocation Loc,
  187. StringRef) {
  188. parseToLocation(Loc);
  189. }
  190. void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPop(SourceLocation Loc,
  191. StringRef) {
  192. parseToLocation(Loc);
  193. }
  194. void ExpandModularHeadersPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
  195. StringRef,
  196. diag::Severity,
  197. StringRef) {
  198. parseToLocation(Loc);
  199. }
  200. void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc, StringRef,
  201. bool, OptionalFileEntryRef,
  202. SrcMgr::CharacteristicKind) {
  203. parseToLocation(Loc);
  204. }
  205. void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
  206. SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
  207. unsigned) {
  208. // FIXME: Figure out whether it's the right location to parse to.
  209. parseToLocation(NameLoc);
  210. }
  211. void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
  212. PragmaWarningSpecifier,
  213. ArrayRef<int>) {
  214. parseToLocation(Loc);
  215. }
  216. void ExpandModularHeadersPPCallbacks::PragmaWarningPush(SourceLocation Loc,
  217. int) {
  218. parseToLocation(Loc);
  219. }
  220. void ExpandModularHeadersPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
  221. parseToLocation(Loc);
  222. }
  223. void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullBegin(
  224. SourceLocation Loc) {
  225. parseToLocation(Loc);
  226. }
  227. void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullEnd(
  228. SourceLocation Loc) {
  229. parseToLocation(Loc);
  230. }
  231. void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok,
  232. const MacroDefinition &,
  233. SourceRange Range,
  234. const MacroArgs *) {
  235. // FIXME: Figure out whether it's the right location to parse to.
  236. parseToLocation(Range.getBegin());
  237. }
  238. void ExpandModularHeadersPPCallbacks::MacroDefined(const Token &MacroNameTok,
  239. const MacroDirective *MD) {
  240. parseToLocation(MD->getLocation());
  241. }
  242. void ExpandModularHeadersPPCallbacks::MacroUndefined(
  243. const Token &, const MacroDefinition &, const MacroDirective *Undef) {
  244. if (Undef)
  245. parseToLocation(Undef->getLocation());
  246. }
  247. void ExpandModularHeadersPPCallbacks::Defined(const Token &MacroNameTok,
  248. const MacroDefinition &,
  249. SourceRange Range) {
  250. // FIXME: Figure out whether it's the right location to parse to.
  251. parseToLocation(Range.getBegin());
  252. }
  253. void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
  254. SourceRange Range, SourceLocation EndifLoc) {
  255. // FIXME: Figure out whether it's the right location to parse to.
  256. parseToLocation(EndifLoc);
  257. }
  258. void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc, SourceRange,
  259. ConditionValueKind) {
  260. parseToLocation(Loc);
  261. }
  262. void ExpandModularHeadersPPCallbacks::Elif(SourceLocation Loc, SourceRange,
  263. ConditionValueKind, SourceLocation) {
  264. parseToLocation(Loc);
  265. }
  266. void ExpandModularHeadersPPCallbacks::Ifdef(SourceLocation Loc, const Token &,
  267. const MacroDefinition &) {
  268. parseToLocation(Loc);
  269. }
  270. void ExpandModularHeadersPPCallbacks::Ifndef(SourceLocation Loc, const Token &,
  271. const MacroDefinition &) {
  272. parseToLocation(Loc);
  273. }
  274. void ExpandModularHeadersPPCallbacks::Else(SourceLocation Loc, SourceLocation) {
  275. parseToLocation(Loc);
  276. }
  277. void ExpandModularHeadersPPCallbacks::Endif(SourceLocation Loc,
  278. SourceLocation) {
  279. parseToLocation(Loc);
  280. }
  281. } // namespace clang::tooling