10 #include "clang/Basic/SourceManager.h"
11 #include "clang/Lex/Lexer.h"
19 StringRef RemoveFirstSuffix(StringRef Str, ArrayRef<const char *>
Suffixes) {
21 if (Str.endswith(
Suffix)) {
22 return Str.substr(0, Str.size() -
Suffix.size());
36 return RemoveFirstSuffix(
37 RemoveFirstSuffix(Str, {
".cc",
".cpp",
".c",
".h",
".hpp"}), {
"Test"});
39 return RemoveFirstSuffix(
40 RemoveFirstSuffix(Str, {
".cc",
".cpp",
".c",
".h",
".hpp"}),
41 {
"_unittest",
"_regtest",
"_test"});
45 size_t FindNextLine(
const char *Text) {
46 size_t EOLIndex = std::strcspn(Text,
"\n");
47 return Text[EOLIndex] ==
'\0' ? EOLIndex : EOLIndex + 1;
51 DetermineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile,
63 StringRef CanonicalInclude = MakeCanonicalName(IncludeFile, Style);
64 if (CanonicalFile.endswith(CanonicalInclude)
65 || CanonicalInclude.endswith(CanonicalFile)) {
69 std::pair<StringRef, StringRef> Parts = CanonicalInclude.split(
"/public/");
70 std::string AltCanonicalInclude =
71 Parts.first.str() +
"/internal/" + Parts.second.str();
72 std::string ProtoCanonicalInclude =
73 Parts.first.str() +
"/proto/" + Parts.second.str();
76 if (CanonicalFile.equals(AltCanonicalInclude) ||
77 CanonicalFile.equals(ProtoCanonicalInclude)) {
87 const FileID FileID, StringRef
FileName,
90 CanonicalFile(MakeCanonicalName(
FileName, Style)) {}
93 SourceLocation HashLocation,
94 SourceLocation EndLocation) {
95 int Offset = FindNextLine(SourceMgr->getCharacterData(EndLocation));
98 IncludeLocations[
FileName].push_back(
99 SourceRange(HashLocation, EndLocation.getLocWithOffset(
Offset)));
100 SourceLocations.push_back(IncludeLocations[
FileName].back());
103 if (IncludeLocations[
FileName].size() > 1)
115 std::string IncludeStmt =
117 : llvm::Twine(
"#include \"" +
FileName +
"\"\n").str();
118 if (SourceLocations.empty()) {
121 IncludeStmt.append(
"\n");
122 return FixItHint::CreateInsertion(
123 SourceMgr->getLocForStartOfFile(CurrentFileID), IncludeStmt);
129 if (!IncludeBucket[IncludeKind].empty()) {
130 for (
const std::string &IncludeEntry : IncludeBucket[IncludeKind]) {
132 const auto &
Location = IncludeLocations[IncludeEntry][0];
133 return FixItHint::CreateInsertion(
Location.getBegin(), IncludeStmt);
134 }
else if (
FileName == IncludeEntry) {
140 const std::string &LastInclude = IncludeBucket[IncludeKind].back();
141 SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();
142 return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(),
152 if (!IncludeBucket[i].empty()) {
153 NonEmptyKind = static_cast<IncludeKinds>(i);
154 if (NonEmptyKind < IncludeKind)
162 if (NonEmptyKind < IncludeKind) {
164 const std::string &LastInclude = IncludeBucket[NonEmptyKind].back();
165 SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();
166 IncludeStmt =
'\n' + IncludeStmt;
167 return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(),
171 const std::string &FirstInclude = IncludeBucket[NonEmptyKind][0];
172 SourceRange FirstIncludeLocation = IncludeLocations[FirstInclude].back();
173 IncludeStmt.append(
"\n");
174 return FixItHint::CreateInsertion(FirstIncludeLocation.getBegin(),
180 llvm::ArrayRef<std::pair<utils::IncludeSorter::IncludeStyle, StringRef>>
182 static constexpr std::pair<utils::IncludeSorter::IncludeStyle, StringRef>
185 return makeArrayRef(Mapping);