summaryrefslogtreecommitdiff
path: root/lib/Format/UsingDeclarationsSorter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/UsingDeclarationsSorter.cpp')
-rw-r--r--lib/Format/UsingDeclarationsSorter.cpp91
1 files changed, 82 insertions, 9 deletions
diff --git a/lib/Format/UsingDeclarationsSorter.cpp b/lib/Format/UsingDeclarationsSorter.cpp
index fb4f59fbc9bc..ef0c7a7d5a45 100644
--- a/lib/Format/UsingDeclarationsSorter.cpp
+++ b/lib/Format/UsingDeclarationsSorter.cpp
@@ -26,6 +26,45 @@ namespace format {
namespace {
+// The order of using declaration is defined as follows:
+// Split the strings by "::" and discard any initial empty strings. The last
+// element of each list is a non-namespace name; all others are namespace
+// names. Sort the lists of names lexicographically, where the sort order of
+// individual names is that all non-namespace names come before all namespace
+// names, and within those groups, names are in case-insensitive lexicographic
+// order.
+int compareLabels(StringRef A, StringRef B) {
+ SmallVector<StringRef, 2> NamesA;
+ A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ SmallVector<StringRef, 2> NamesB;
+ B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ size_t SizeA = NamesA.size();
+ size_t SizeB = NamesB.size();
+ for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
+ if (I + 1 == SizeA) {
+ // I is the last index of NamesA and NamesA[I] is a non-namespace name.
+
+ // Non-namespace names come before all namespace names.
+ if (SizeB > SizeA)
+ return -1;
+
+ // Two names within a group compare case-insensitively.
+ return NamesA[I].compare_lower(NamesB[I]);
+ }
+
+ // I is the last index of NamesB and NamesB[I] is a non-namespace name.
+ // Non-namespace names come before all namespace names.
+ if (I + 1 == SizeB)
+ return 1;
+
+ // Two namespaces names within a group compare case-insensitively.
+ int C = NamesA[I].compare_lower(NamesB[I]);
+ if (C != 0)
+ return C;
+ }
+ return 0;
+}
+
struct UsingDeclaration {
const AnnotatedLine *Line;
std::string Label;
@@ -34,7 +73,7 @@ struct UsingDeclaration {
: Line(Line), Label(Label) {}
bool operator<(const UsingDeclaration &Other) const {
- return Label < Other.Label;
+ return compareLabels(Label, Other.Label) < 0;
}
};
@@ -76,10 +115,42 @@ std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
void endUsingDeclarationBlock(
SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
+ bool BlockAffected = false;
+ for (const UsingDeclaration &Declaration : *UsingDeclarations) {
+ if (Declaration.Line->Affected) {
+ BlockAffected = true;
+ break;
+ }
+ }
+ if (!BlockAffected) {
+ UsingDeclarations->clear();
+ return;
+ }
SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
UsingDeclarations->begin(), UsingDeclarations->end());
- std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end());
+ std::stable_sort(SortedUsingDeclarations.begin(),
+ SortedUsingDeclarations.end());
+ SortedUsingDeclarations.erase(
+ std::unique(SortedUsingDeclarations.begin(),
+ SortedUsingDeclarations.end(),
+ [](const UsingDeclaration &a, const UsingDeclaration &b) {
+ return a.Label == b.Label;
+ }),
+ SortedUsingDeclarations.end());
for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
+ if (I >= SortedUsingDeclarations.size()) {
+ // This using declaration has been deduplicated, delete it.
+ auto Begin =
+ (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
+ auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
+ auto Range = CharSourceRange::getCharRange(Begin, End);
+ auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
+ if (Err) {
+ llvm::errs() << "Error while sorting using declarations: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ continue;
+ }
if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
continue;
auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
@@ -112,7 +183,7 @@ UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
const FormatStyle &Style)
: TokenAnalyzer(Env, Style) {}
-tooling::Replacements UsingDeclarationsSorter::analyze(
+std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) {
const SourceManager &SourceMgr = Env.getSourceManager();
@@ -121,15 +192,17 @@ tooling::Replacements UsingDeclarationsSorter::analyze(
tooling::Replacements Fixes;
SmallVector<UsingDeclaration, 4> UsingDeclarations;
for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
- if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
- !AnnotatedLines[I]->startsWith(tok::kw_using) ||
- AnnotatedLines[I]->First->Finalized) {
+ const auto *FirstTok = AnnotatedLines[I]->First;
+ if (AnnotatedLines[I]->InPPDirective ||
+ !AnnotatedLines[I]->startsWith(tok::kw_using) || FirstTok->Finalized) {
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
continue;
}
- if (AnnotatedLines[I]->First->NewlinesBefore > 1)
+ if (FirstTok->NewlinesBefore > 1)
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
- std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
+ const auto *UsingTok =
+ FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
+ std::string Label = computeUsingDeclarationLabel(UsingTok);
if (Label.empty()) {
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
continue;
@@ -137,7 +210,7 @@ tooling::Replacements UsingDeclarationsSorter::analyze(
UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
}
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
- return Fixes;
+ return {Fixes, 0};
}
} // namespace format