IncludeInserter.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //===-------- IncludeInserter.cpp - clang-tidy ----------------------------===//
  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 "IncludeInserter.h"
  9. #include "clang/Lex/PPCallbacks.h"
  10. #include "clang/Lex/Preprocessor.h"
  11. #include "clang/Lex/Token.h"
  12. #include <optional>
  13. namespace clang::tidy::utils {
  14. class IncludeInserterCallback : public PPCallbacks {
  15. public:
  16. explicit IncludeInserterCallback(IncludeInserter *Inserter)
  17. : Inserter(Inserter) {}
  18. // Implements PPCallbacks::InclusionDirective(). Records the names and source
  19. // locations of the inclusions in the main source file being processed.
  20. void InclusionDirective(SourceLocation HashLocation,
  21. const Token &IncludeToken, StringRef FileNameRef,
  22. bool IsAngled, CharSourceRange FileNameRange,
  23. OptionalFileEntryRef /*IncludedFile*/,
  24. StringRef /*SearchPath*/, StringRef /*RelativePath*/,
  25. const Module * /*ImportedModule*/,
  26. SrcMgr::CharacteristicKind /*FileType*/) override {
  27. Inserter->addInclude(FileNameRef, IsAngled, HashLocation,
  28. IncludeToken.getEndLoc());
  29. }
  30. private:
  31. IncludeInserter *Inserter;
  32. };
  33. IncludeInserter::IncludeInserter(IncludeSorter::IncludeStyle Style,
  34. bool SelfContainedDiags)
  35. : Style(Style), SelfContainedDiags(SelfContainedDiags) {}
  36. void IncludeInserter::registerPreprocessor(Preprocessor *PP) {
  37. assert(PP && "PP shouldn't be null");
  38. SourceMgr = &PP->getSourceManager();
  39. // If this gets registered multiple times, clear the maps
  40. if (!IncludeSorterByFile.empty())
  41. IncludeSorterByFile.clear();
  42. if (!InsertedHeaders.empty())
  43. InsertedHeaders.clear();
  44. PP->addPPCallbacks(std::make_unique<IncludeInserterCallback>(this));
  45. }
  46. IncludeSorter &IncludeInserter::getOrCreate(FileID FileID) {
  47. assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
  48. "registerPreprocessor()?");
  49. // std::unique_ptr is cheap to construct, so force a construction now to save
  50. // the lookup needed if we were to insert into the map.
  51. std::unique_ptr<IncludeSorter> &Entry = IncludeSorterByFile[FileID];
  52. if (!Entry) {
  53. // If it wasn't found, Entry will be default constructed to nullptr.
  54. Entry = std::make_unique<IncludeSorter>(
  55. SourceMgr, FileID,
  56. SourceMgr->getFilename(SourceMgr->getLocForStartOfFile(FileID)), Style);
  57. }
  58. return *Entry;
  59. }
  60. std::optional<FixItHint>
  61. IncludeInserter::createIncludeInsertion(FileID FileID, llvm::StringRef Header) {
  62. bool IsAngled = Header.consume_front("<");
  63. if (IsAngled != Header.consume_back(">"))
  64. return std::nullopt;
  65. // We assume the same Header will never be included both angled and not
  66. // angled.
  67. // In self contained diags mode we don't track what headers we have already
  68. // inserted.
  69. if (!SelfContainedDiags && !InsertedHeaders[FileID].insert(Header).second)
  70. return std::nullopt;
  71. return getOrCreate(FileID).createIncludeInsertion(Header, IsAngled);
  72. }
  73. std::optional<FixItHint>
  74. IncludeInserter::createMainFileIncludeInsertion(StringRef Header) {
  75. assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
  76. "registerPreprocessor()?");
  77. return createIncludeInsertion(SourceMgr->getMainFileID(), Header);
  78. }
  79. void IncludeInserter::addInclude(StringRef FileName, bool IsAngled,
  80. SourceLocation HashLocation,
  81. SourceLocation EndLocation) {
  82. assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
  83. "registerPreprocessor()?");
  84. FileID FileID = SourceMgr->getFileID(HashLocation);
  85. getOrCreate(FileID).addInclude(FileName, IsAngled, HashLocation, EndLocation);
  86. }
  87. } // namespace clang::tidy::utils