11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Lex/PPCallbacks.h" 13 #include "clang/Lex/Preprocessor.h" 22 class IncludeOrderPPCallbacks :
public PPCallbacks {
24 explicit IncludeOrderPPCallbacks(ClangTidyCheck &Check, SourceManager &SM)
25 : LookForMainModule(true), Check(Check), SM(SM) {}
27 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
29 CharSourceRange FilenameRange,
const FileEntry *File,
30 StringRef SearchPath, StringRef RelativePath,
31 const Module *Imported,
32 SrcMgr::CharacteristicKind FileType)
override;
33 void EndOfMainFile()
override;
36 struct IncludeDirective {
44 typedef std::vector<IncludeDirective> FileIncludes;
45 std::map<clang::FileID, FileIncludes> IncludeDirectives;
46 bool LookForMainModule;
48 ClangTidyCheck &Check;
54 Compiler.getPreprocessor().addPPCallbacks(
55 ::llvm::make_unique<IncludeOrderPPCallbacks>(
56 *
this, Compiler.getSourceManager()));
65 if (Filename.startswith(
"llvm/") || Filename.startswith(
"llvm-c/") ||
66 Filename.startswith(
"clang/") || Filename.startswith(
"clang-c/"))
70 if (IsAngled || Filename.startswith(
"gtest/"))
77 void IncludeOrderPPCallbacks::InclusionDirective(
78 SourceLocation HashLoc,
const Token &IncludeTok, StringRef
FileName,
79 bool IsAngled, CharSourceRange FilenameRange,
const FileEntry *
File,
80 StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
81 SrcMgr::CharacteristicKind FileType) {
85 if (LookForMainModule && !IsAngled) {
86 ID.IsMainModule =
true;
87 LookForMainModule =
false;
91 IncludeDirectives[SM.getFileID(HashLoc)].push_back(std::move(ID));
94 void IncludeOrderPPCallbacks::EndOfMainFile() {
95 LookForMainModule =
true;
96 if (IncludeDirectives.empty())
106 for (
auto &Bucket : IncludeDirectives) {
107 auto &FileDirectives = Bucket.second;
108 std::vector<unsigned> Blocks(1, 0);
109 for (
unsigned I = 1, E = FileDirectives.size(); I != E; ++I)
110 if (SM.getExpansionLineNumber(FileDirectives[I].Loc) !=
111 SM.getExpansionLineNumber(FileDirectives[I - 1].
Loc) + 1)
113 Blocks.push_back(FileDirectives.size());
116 std::vector<unsigned> IncludeIndices;
117 for (
unsigned I = 0, E = FileDirectives.size(); I != E; ++I)
118 IncludeIndices.push_back(I);
121 for (
unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
122 std::sort(IncludeIndices.begin() + Blocks[BI],
123 IncludeIndices.begin() + Blocks[BI + 1],
124 [&FileDirectives](
unsigned LHSI,
unsigned RHSI) {
125 IncludeDirective &LHS = FileDirectives[LHSI];
126 IncludeDirective &RHS = FileDirectives[RHSI];
129 getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
131 getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
133 return std::tie(PriorityLHS, LHS.Filename) <
134 std::tie(PriorityRHS, RHS.Filename);
139 for (
unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
142 for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
143 if (IncludeIndices[I] != I)
150 auto D = Check.diag(FileDirectives[I].
Loc,
151 "#includes are not sorted properly");
154 for (; I != E; ++I) {
155 if (IncludeIndices[I] == I)
157 const IncludeDirective &CopyFrom = FileDirectives[IncludeIndices[I]];
159 SourceLocation FromLoc = CopyFrom.Range.getBegin();
160 const char *FromData = SM.getCharacterData(FromLoc);
161 unsigned FromLen = std::strcspn(FromData,
"\n");
163 StringRef FixedName(FromData, FromLen);
165 SourceLocation ToLoc = FileDirectives[I].Range.getBegin();
166 const char *ToData = SM.getCharacterData(ToLoc);
167 unsigned ToLen = std::strcspn(ToData,
"\n");
169 CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
171 D << FixItHint::CreateReplacement(ToRange, FixedName);
176 IncludeDirectives.clear();
SourceLocation Loc
'#' location in the include directive
Some operations such as code completion produce a set of candidates.
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
std::string Filename
Filename as a string.
bool IsAngled
true if this was an include with angle brackets
bool IsMainModule
true if this was the first include in a file
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
static int getPriority(StringRef Filename, bool IsAngled, bool IsMainModule)