| //===-------- IncludeInserter.cpp - clang-tidy ----------------------------===// |
| // |
| // 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 "IncludeInserter.h" |
| #include "clang/Lex/PPCallbacks.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Lex/Token.h" |
| |
| namespace clang { |
| namespace tidy { |
| namespace utils { |
| |
| class IncludeInserterCallback : public PPCallbacks { |
| public: |
| explicit IncludeInserterCallback(IncludeInserter *Inserter) |
| : Inserter(Inserter) {} |
| // Implements PPCallbacks::InclusionDirective(). Records the names and source |
| // locations of the inclusions in the main source file being processed. |
| void InclusionDirective(SourceLocation HashLocation, |
| const Token &IncludeToken, StringRef FileNameRef, |
| bool IsAngled, CharSourceRange FileNameRange, |
| const FileEntry * /*IncludedFile*/, |
| StringRef /*SearchPath*/, StringRef /*RelativePath*/, |
| const Module * /*ImportedModule*/, |
| SrcMgr::CharacteristicKind /*FileType*/) override { |
| Inserter->addInclude(FileNameRef, IsAngled, HashLocation, |
| IncludeToken.getEndLoc()); |
| } |
| |
| private: |
| IncludeInserter *Inserter; |
| }; |
| |
| IncludeInserter::IncludeInserter(IncludeSorter::IncludeStyle Style) |
| : Style(Style) {} |
| |
| void IncludeInserter::registerPreprocessor(Preprocessor *PP) { |
| assert(PP && "PP shouldn't be null"); |
| SourceMgr = &PP->getSourceManager(); |
| |
| // If this gets registered multiple times, clear the maps |
| if (!IncludeSorterByFile.empty()) |
| IncludeSorterByFile.clear(); |
| if (!InsertedHeaders.empty()) |
| InsertedHeaders.clear(); |
| PP->addPPCallbacks(std::make_unique<IncludeInserterCallback>(this)); |
| } |
| |
| IncludeSorter &IncludeInserter::getOrCreate(FileID FileID) { |
| assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call " |
| "registerPreprocessor()?"); |
| // std::unique_ptr is cheap to construct, so force a construction now to save |
| // the lookup needed if we were to insert into the map. |
| std::unique_ptr<IncludeSorter> &Entry = IncludeSorterByFile[FileID]; |
| if (!Entry) { |
| // If it wasn't found, Entry will be default constructed to nullptr. |
| Entry = std::make_unique<IncludeSorter>( |
| SourceMgr, FileID, |
| SourceMgr->getFilename(SourceMgr->getLocForStartOfFile(FileID)), Style); |
| } |
| return *Entry; |
| } |
| |
| llvm::Optional<FixItHint> |
| IncludeInserter::createIncludeInsertion(FileID FileID, llvm::StringRef Header) { |
| bool IsAngled = Header.consume_front("<"); |
| if (IsAngled != Header.consume_back(">")) |
| return llvm::None; |
| // We assume the same Header will never be included both angled and not |
| // angled. |
| if (!InsertedHeaders[FileID].insert(Header).second) |
| return llvm::None; |
| |
| return getOrCreate(FileID).createIncludeInsertion(Header, IsAngled); |
| } |
| |
| llvm::Optional<FixItHint> |
| IncludeInserter::createMainFileIncludeInsertion(StringRef Header) { |
| assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call " |
| "registerPreprocessor()?"); |
| return createIncludeInsertion(SourceMgr->getMainFileID(), Header); |
| } |
| |
| void IncludeInserter::addInclude(StringRef FileName, bool IsAngled, |
| SourceLocation HashLocation, |
| SourceLocation EndLocation) { |
| assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call " |
| "registerPreprocessor()?"); |
| FileID FileID = SourceMgr->getFileID(HashLocation); |
| getOrCreate(FileID).addInclude(FileName, IsAngled, HashLocation, EndLocation); |
| } |
| |
| } // namespace utils |
| } // namespace tidy |
| } // namespace clang |