10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/PPCallbacks.h"
12 #include "clang/Lex/Preprocessor.h"
18 namespace llvm_check {
21 class IncludeOrderPPCallbacks :
public PPCallbacks {
23 explicit IncludeOrderPPCallbacks(ClangTidyCheck &Check,
24 const 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;
49 const SourceManager &SM;
55 Preprocessor *ModuleExpanderPP) {
56 PP->addPPCallbacks(::std::make_unique<IncludeOrderPPCallbacks>(*
this, SM));
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) {
84 IncludeDirective ID = {HashLoc, FilenameRange, std::string(
FileName),
86 if (LookForMainModule && !
IsAngled) {
87 ID.IsMainModule =
true;
88 LookForMainModule =
false;
92 IncludeDirectives[SM.getFileID(HashLoc)].push_back(std::move(ID));
95 void IncludeOrderPPCallbacks::EndOfMainFile() {
96 LookForMainModule =
true;
97 if (IncludeDirectives.empty())
107 for (
auto &Bucket : IncludeDirectives) {
108 auto &FileDirectives = Bucket.second;
109 std::vector<unsigned> Blocks(1, 0);
110 for (
unsigned I = 1,
E = FileDirectives.size(); I !=
E; ++I)
111 if (SM.getExpansionLineNumber(FileDirectives[I].Loc) !=
112 SM.getExpansionLineNumber(FileDirectives[I - 1].
Loc) + 1)
114 Blocks.push_back(FileDirectives.size());
117 std::vector<unsigned> IncludeIndices;
118 for (
unsigned I = 0,
E = FileDirectives.size(); I !=
E; ++I)
119 IncludeIndices.push_back(I);
122 for (
unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
123 std::sort(IncludeIndices.begin() + Blocks[BI],
124 IncludeIndices.begin() + Blocks[BI + 1],
125 [&FileDirectives](
unsigned LHSI,
unsigned RHSI) {
126 IncludeDirective &LHS = FileDirectives[LHSI];
127 IncludeDirective &RHS = FileDirectives[RHSI];
130 getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
132 getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
134 return std::tie(PriorityLHS, LHS.Filename) <
135 std::tie(PriorityRHS, RHS.Filename);
140 for (
unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
143 for (I = Blocks[BI],
E = Blocks[BI + 1]; I !=
E; ++I)
144 if (IncludeIndices[I] != I)
151 auto D = Check.diag(FileDirectives[I].
Loc,
152 "#includes are not sorted properly");
155 for (; I !=
E; ++I) {
156 if (IncludeIndices[I] == I)
158 const IncludeDirective &CopyFrom = FileDirectives[IncludeIndices[I]];
160 SourceLocation FromLoc = CopyFrom.Range.getBegin();
161 const char *FromData = SM.getCharacterData(FromLoc);
162 unsigned FromLen = std::strcspn(FromData,
"\n");
164 StringRef FixedName(FromData, FromLen);
166 SourceLocation ToLoc = FileDirectives[I].Range.getBegin();
167 const char *ToData = SM.getCharacterData(ToLoc);
168 unsigned ToLen = std::strcspn(ToData,
"\n");
170 CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
172 D << FixItHint::CreateReplacement(ToRange, FixedName);
177 IncludeDirectives.clear();