blob: 6f3eed49831fd3d60d832ac623cfcff487f5e3b7 [file] [log] [blame]
//===-------- 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