clang: lib/Format/UsingDeclarationsSorter.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/Regex.h"
19
20#include
21
22#define DEBUG_TYPE "using-declarations-sorter"
23
25namespace format {
26
27namespace {
28
29
30
31
32
33
34
35
36int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
37 SmallVector<StringRef, 2> NamesA;
38 A.split(NamesA, "::", -1, false);
39 SmallVector<StringRef, 2> NamesB;
40 B.split(NamesB, "::", -1, false);
41 size_t SizeA = NamesA.size();
42 size_t SizeB = NamesB.size();
43 for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
44 if (I + 1 == SizeA) {
45
46
47
48 if (SizeB > SizeA)
49 return -1;
50
51
52 return NamesA[I].compare_insensitive(NamesB[I]);
53 }
54
55
56
57 if (I + 1 == SizeB)
58 return 1;
59
60
61 int C = NamesA[I].compare_insensitive(NamesB[I]);
62 if (C != 0)
63 return C;
64 }
65 return 0;
66}
67
68int compareLabelsLexicographic(StringRef A, StringRef B) {
69 SmallVector<StringRef, 2> NamesA;
70 A.split(NamesA, "::", -1, false);
71 SmallVector<StringRef, 2> NamesB;
72 B.split(NamesB, "::", -1, false);
73 size_t SizeA = NamesA.size();
74 size_t SizeB = NamesB.size();
75 for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
76
77 int C = NamesA[I].compare_insensitive(NamesB[I]);
78 if (C != 0)
79 return C;
80 }
81 if (SizeA < SizeB)
82 return -1;
83 return SizeA == SizeB ? 0 : 1;
84}
85
86int compareLabels(
87 StringRef A, StringRef B,
90 return compareLabelsLexicographicNumeric(A, B);
91 return compareLabelsLexicographic(A, B);
92}
93
94struct UsingDeclaration {
95 const AnnotatedLine *Line;
97
98 UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
100};
101
102
103
104
105
106
107
108
109
110std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
111 assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
112 std::string Label;
113 const FormatToken *Tok = UsingTok->Next;
114 if (Tok && Tok->is(tok::kw_typename)) {
115 Label.append("typename ");
116 Tok = Tok->Next;
117 }
118 if (Tok && Tok->is(tok::coloncolon)) {
119 Label.append("::");
120 Tok = Tok->Next;
121 }
122 bool HasIdentifier = false;
123 while (Tok && Tok->is(tok::identifier)) {
124 HasIdentifier = true;
125 Label.append(Tok->TokenText.str());
126 Tok = Tok->Next;
127 if (!Tok || Tok->isNot(tok::coloncolon))
128 break;
129 Label.append("::");
130 Tok = Tok->Next;
131 }
132 if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
134 return "";
135}
136
137void endUsingDeclarationBlock(
138 SmallVectorImpl *UsingDeclarations,
139 const SourceManager &SourceMgr, tooling::Replacements *Fixes,
141 bool BlockAffected = false;
142 for (const UsingDeclaration &Declaration : *UsingDeclarations) {
144 BlockAffected = true;
145 break;
146 }
147 }
148 if (!BlockAffected) {
149 UsingDeclarations->clear();
150 return;
151 }
152 SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
153 UsingDeclarations->begin(), UsingDeclarations->end());
154 auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
155 const UsingDeclaration &Rhs) -> bool {
156 return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
157 };
158 llvm::stable_sort(SortedUsingDeclarations, Comp);
159 SortedUsingDeclarations.erase(
160 std::unique(SortedUsingDeclarations.begin(),
161 SortedUsingDeclarations.end(),
162 [](const UsingDeclaration &a, const UsingDeclaration &b) {
163 return a.Label == b.Label;
164 }),
165 SortedUsingDeclarations.end());
166 for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
167 if (I >= SortedUsingDeclarations.size()) {
168
170 (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
171 auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
173 auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
174 if (Err) {
175 llvm::errs() << "Error while sorting using declarations: "
176 << llvm::toString(std::move(Err)) << "\n";
177 }
178 continue;
179 }
180 if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
181 continue;
182 auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
183 auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
184 auto SortedBegin =
185 SortedUsingDeclarations[I].Line->First->Tok.getLocation();
186 auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
187 StringRef Text(SourceMgr.getCharacterData(SortedBegin),
188 SourceMgr.getCharacterData(SortedEnd) -
189 SourceMgr.getCharacterData(SortedBegin));
190 LLVM_DEBUG({
191 StringRef OldText(SourceMgr.getCharacterData(Begin),
192 SourceMgr.getCharacterData(End) -
193 SourceMgr.getCharacterData(Begin));
194 llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
195 });
197 auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
198 if (Err) {
199 llvm::errs() << "Error while sorting using declarations: "
200 << llvm::toString(std::move(Err)) << "\n";
201 }
202 }
203 UsingDeclarations->clear();
204}
205
206}
207
211
220 const auto *FirstTok = Line->First;
221 if (Line->InPPDirective || ->startsWith(tok::kw_using) ||
222 FirstTok->Finalized) {
223 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
225 continue;
226 }
227 if (FirstTok->NewlinesBefore > 1) {
228 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
230 }
231 const auto *UsingTok =
232 FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
233 std::string Label = computeUsingDeclarationLabel(UsingTok);
234 if (Label.empty()) {
235 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
237 continue;
238 }
239 UsingDeclarations.push_back(UsingDeclaration(Line, Label));
240 }
241 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
243 return {Fixes, 0};
244}
245
246}
247}
Various functions to configurably format source code.
This file declares UsingDeclarationsSorter, a TokenAnalyzer that sorts consecutive using declarations...
static CharSourceRange getCharRange(SourceRange R)
This class handles loading and caching of source files into memory.
bool computeAffectedLines(SmallVectorImpl< AnnotatedLine * > &Lines)
SourceManager & getSourceManager() const
AffectedRangeManager AffectedRangeMgr
Determines extra information about the tokens comprising an UnwrappedLine.
std::pair< tooling::Replacements, unsigned > analyze(TokenAnnotator &Annotator, SmallVectorImpl< AnnotatedLine * > &AnnotatedLines, FormatTokenLexer &Tokens) override
UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style)
bool Comp(InterpState &S, CodePtr OpPC)
- Pops the value from the stack.
The JSON file list parser is used to communicate input to InstallAPI.
The FormatStyle is used to configure the formatting to follow specific guidelines.
SortUsingDeclarationsOptions
Using declaration sorting options.
@ SUD_LexicographicNumeric
Using declarations are sorted in the order defined as follows: Split the strings by :: and discard an...
SortUsingDeclarationsOptions SortUsingDeclarations
Controls if and how clang-format will sort using declarations.