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