16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Regex.h"
21 #define DEBUG_TYPE "using-declarations-sorter"
35 int compareLabels(StringRef A, StringRef B) {
36 SmallVector<StringRef, 2> NamesA;
37 A.split(NamesA,
"::", -1,
false);
38 SmallVector<StringRef, 2> NamesB;
39 B.split(NamesB,
"::", -1,
false);
40 size_t SizeA = NamesA.size();
41 size_t SizeB = NamesB.size();
42 for (
size_t I = 0, E =
std::min(SizeA, SizeB); I < E; ++I) {
51 return NamesA[I].compare_insensitive(NamesB[I]);
60 int C = NamesA[I].compare_insensitive(NamesB[I]);
67 struct UsingDeclaration {
74 bool operator<(
const UsingDeclaration &Other)
const {
75 return compareLabels(
Label, Other.Label) < 0;
87 std::string computeUsingDeclarationLabel(
const FormatToken *UsingTok) {
88 assert(UsingTok && UsingTok->is(tok::kw_using) &&
"Expecting a using token");
90 const FormatToken *Tok = UsingTok->Next;
91 if (Tok && Tok->is(tok::kw_typename)) {
92 Label.append(
"typename ");
95 if (Tok && Tok->is(tok::coloncolon)) {
99 bool HasIdentifier =
false;
100 while (Tok && Tok->is(tok::identifier)) {
101 HasIdentifier =
true;
102 Label.append(Tok->TokenText.str());
104 if (!Tok || Tok->isNot(tok::coloncolon))
109 if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
114 void endUsingDeclarationBlock(
115 SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
116 const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
117 bool BlockAffected =
false;
118 for (
const UsingDeclaration &Declaration : *UsingDeclarations) {
120 BlockAffected =
true;
124 if (!BlockAffected) {
125 UsingDeclarations->clear();
128 SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
129 UsingDeclarations->begin(), UsingDeclarations->end());
130 llvm::stable_sort(SortedUsingDeclarations);
131 SortedUsingDeclarations.erase(
132 std::unique(SortedUsingDeclarations.begin(),
133 SortedUsingDeclarations.end(),
134 [](
const UsingDeclaration &a,
const UsingDeclaration &
b) {
135 return a.Label == b.Label;
137 SortedUsingDeclarations.end());
138 for (
size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
139 if (I >= SortedUsingDeclarations.size()) {
142 (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
143 auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
145 auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range,
""));
147 llvm::errs() <<
"Error while sorting using declarations: "
152 if ((*UsingDeclarations)[I].
Line == SortedUsingDeclarations[I].
Line)
154 auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
155 auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
157 SortedUsingDeclarations[I].Line->First->Tok.getLocation();
158 auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
159 StringRef
Text(SourceMgr.getCharacterData(SortedBegin),
160 SourceMgr.getCharacterData(SortedEnd) -
161 SourceMgr.getCharacterData(SortedBegin));
163 StringRef OldText(SourceMgr.getCharacterData(
Begin),
164 SourceMgr.getCharacterData(
End) -
165 SourceMgr.getCharacterData(
Begin));
166 llvm::dbgs() <<
"Replacing '" << OldText <<
"' with '" <<
Text <<
"'\n";
169 auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range,
Text));
171 llvm::errs() <<
"Error while sorting using declarations: "
175 UsingDeclarations->clear();
192 const auto *FirstTok =
Line->First;
193 if (
Line->InPPDirective || !
Line->startsWith(tok::kw_using) ||
194 FirstTok->Finalized) {
195 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
198 if (FirstTok->NewlinesBefore > 1)
199 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
200 const auto *UsingTok =
201 FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
204 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
207 UsingDeclarations.push_back(UsingDeclaration(
Line,
Label));
209 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);