10b57cec5SDimitry Andric //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements UsingDeclarationsSorter, a TokenAnalyzer that
110b57cec5SDimitry Andric /// sorts consecutive using declarations.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "UsingDeclarationsSorter.h"
16*bdd1243dSDimitry Andric #include "clang/Format/Format.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric #include <algorithm>
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric #define DEBUG_TYPE "using-declarations-sorter"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric namespace clang {
250b57cec5SDimitry Andric namespace format {
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric namespace {
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric // The order of using declaration is defined as follows:
300b57cec5SDimitry Andric // Split the strings by "::" and discard any initial empty strings. The last
310b57cec5SDimitry Andric // element of each list is a non-namespace name; all others are namespace
320b57cec5SDimitry Andric // names. Sort the lists of names lexicographically, where the sort order of
330b57cec5SDimitry Andric // individual names is that all non-namespace names come before all namespace
340b57cec5SDimitry Andric // names, and within those groups, names are in case-insensitive lexicographic
350b57cec5SDimitry Andric // order.
compareLabelsLexicographicNumeric(StringRef A,StringRef B)36*bdd1243dSDimitry Andric int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
370b57cec5SDimitry Andric SmallVector<StringRef, 2> NamesA;
380b57cec5SDimitry Andric A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
390b57cec5SDimitry Andric SmallVector<StringRef, 2> NamesB;
400b57cec5SDimitry Andric B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
410b57cec5SDimitry Andric size_t SizeA = NamesA.size();
420b57cec5SDimitry Andric size_t SizeB = NamesB.size();
430b57cec5SDimitry Andric for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
440b57cec5SDimitry Andric if (I + 1 == SizeA) {
450b57cec5SDimitry Andric // I is the last index of NamesA and NamesA[I] is a non-namespace name.
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric // Non-namespace names come before all namespace names.
480b57cec5SDimitry Andric if (SizeB > SizeA)
490b57cec5SDimitry Andric return -1;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric // Two names within a group compare case-insensitively.
52fe6060f1SDimitry Andric return NamesA[I].compare_insensitive(NamesB[I]);
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric // I is the last index of NamesB and NamesB[I] is a non-namespace name.
560b57cec5SDimitry Andric // Non-namespace names come before all namespace names.
570b57cec5SDimitry Andric if (I + 1 == SizeB)
580b57cec5SDimitry Andric return 1;
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric // Two namespaces names within a group compare case-insensitively.
61fe6060f1SDimitry Andric int C = NamesA[I].compare_insensitive(NamesB[I]);
620b57cec5SDimitry Andric if (C != 0)
630b57cec5SDimitry Andric return C;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric return 0;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
compareLabelsLexicographic(StringRef A,StringRef B)68*bdd1243dSDimitry Andric int compareLabelsLexicographic(StringRef A, StringRef B) {
69*bdd1243dSDimitry Andric SmallVector<StringRef, 2> NamesA;
70*bdd1243dSDimitry Andric A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
71*bdd1243dSDimitry Andric SmallVector<StringRef, 2> NamesB;
72*bdd1243dSDimitry Andric B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
73*bdd1243dSDimitry Andric size_t SizeA = NamesA.size();
74*bdd1243dSDimitry Andric size_t SizeB = NamesB.size();
75*bdd1243dSDimitry Andric for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
76*bdd1243dSDimitry Andric // Two namespaces names within a group compare case-insensitively.
77*bdd1243dSDimitry Andric int C = NamesA[I].compare_insensitive(NamesB[I]);
78*bdd1243dSDimitry Andric if (C != 0)
79*bdd1243dSDimitry Andric return C;
80*bdd1243dSDimitry Andric }
81*bdd1243dSDimitry Andric if (SizeA < SizeB)
82*bdd1243dSDimitry Andric return -1;
83*bdd1243dSDimitry Andric return SizeA == SizeB ? 0 : 1;
84*bdd1243dSDimitry Andric }
85*bdd1243dSDimitry Andric
compareLabels(StringRef A,StringRef B,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)86*bdd1243dSDimitry Andric int compareLabels(
87*bdd1243dSDimitry Andric StringRef A, StringRef B,
88*bdd1243dSDimitry Andric FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
89*bdd1243dSDimitry Andric if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric)
90*bdd1243dSDimitry Andric return compareLabelsLexicographicNumeric(A, B);
91*bdd1243dSDimitry Andric return compareLabelsLexicographic(A, B);
92*bdd1243dSDimitry Andric }
93*bdd1243dSDimitry Andric
940b57cec5SDimitry Andric struct UsingDeclaration {
950b57cec5SDimitry Andric const AnnotatedLine *Line;
960b57cec5SDimitry Andric std::string Label;
970b57cec5SDimitry Andric
UsingDeclarationclang::format::__anon5801d5820111::UsingDeclaration980b57cec5SDimitry Andric UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
990b57cec5SDimitry Andric : Line(Line), Label(Label) {}
1000b57cec5SDimitry Andric };
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric /// Computes the label of a using declaration starting at tthe using token
1030b57cec5SDimitry Andric /// \p UsingTok.
1040b57cec5SDimitry Andric /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
1050b57cec5SDimitry Andric /// Note that this detects specifically using declarations, as in:
1060b57cec5SDimitry Andric /// using A::B::C;
1070b57cec5SDimitry Andric /// and not type aliases, as in:
1080b57cec5SDimitry Andric /// using A = B::C;
1090b57cec5SDimitry Andric /// Type aliases are in general not safe to permute.
computeUsingDeclarationLabel(const FormatToken * UsingTok)1100b57cec5SDimitry Andric std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
1110b57cec5SDimitry Andric assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
1120b57cec5SDimitry Andric std::string Label;
1130b57cec5SDimitry Andric const FormatToken *Tok = UsingTok->Next;
1140b57cec5SDimitry Andric if (Tok && Tok->is(tok::kw_typename)) {
1150b57cec5SDimitry Andric Label.append("typename ");
1160b57cec5SDimitry Andric Tok = Tok->Next;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric if (Tok && Tok->is(tok::coloncolon)) {
1190b57cec5SDimitry Andric Label.append("::");
1200b57cec5SDimitry Andric Tok = Tok->Next;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric bool HasIdentifier = false;
1230b57cec5SDimitry Andric while (Tok && Tok->is(tok::identifier)) {
1240b57cec5SDimitry Andric HasIdentifier = true;
1250b57cec5SDimitry Andric Label.append(Tok->TokenText.str());
1260b57cec5SDimitry Andric Tok = Tok->Next;
1270b57cec5SDimitry Andric if (!Tok || Tok->isNot(tok::coloncolon))
1280b57cec5SDimitry Andric break;
1290b57cec5SDimitry Andric Label.append("::");
1300b57cec5SDimitry Andric Tok = Tok->Next;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
1330b57cec5SDimitry Andric return Label;
1340b57cec5SDimitry Andric return "";
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric
endUsingDeclarationBlock(SmallVectorImpl<UsingDeclaration> * UsingDeclarations,const SourceManager & SourceMgr,tooling::Replacements * Fixes,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)1370b57cec5SDimitry Andric void endUsingDeclarationBlock(
1380b57cec5SDimitry Andric SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
139*bdd1243dSDimitry Andric const SourceManager &SourceMgr, tooling::Replacements *Fixes,
140*bdd1243dSDimitry Andric FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
1410b57cec5SDimitry Andric bool BlockAffected = false;
1420b57cec5SDimitry Andric for (const UsingDeclaration &Declaration : *UsingDeclarations) {
1430b57cec5SDimitry Andric if (Declaration.Line->Affected) {
1440b57cec5SDimitry Andric BlockAffected = true;
1450b57cec5SDimitry Andric break;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric if (!BlockAffected) {
1490b57cec5SDimitry Andric UsingDeclarations->clear();
1500b57cec5SDimitry Andric return;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
1530b57cec5SDimitry Andric UsingDeclarations->begin(), UsingDeclarations->end());
154*bdd1243dSDimitry Andric auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
155*bdd1243dSDimitry Andric const UsingDeclaration &Rhs) -> bool {
156*bdd1243dSDimitry Andric return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
157*bdd1243dSDimitry Andric };
158*bdd1243dSDimitry Andric llvm::stable_sort(SortedUsingDeclarations, Comp);
1590b57cec5SDimitry Andric SortedUsingDeclarations.erase(
1600b57cec5SDimitry Andric std::unique(SortedUsingDeclarations.begin(),
1610b57cec5SDimitry Andric SortedUsingDeclarations.end(),
1620b57cec5SDimitry Andric [](const UsingDeclaration &a, const UsingDeclaration &b) {
1630b57cec5SDimitry Andric return a.Label == b.Label;
1640b57cec5SDimitry Andric }),
1650b57cec5SDimitry Andric SortedUsingDeclarations.end());
1660b57cec5SDimitry Andric for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
1670b57cec5SDimitry Andric if (I >= SortedUsingDeclarations.size()) {
1680b57cec5SDimitry Andric // This using declaration has been deduplicated, delete it.
1690b57cec5SDimitry Andric auto Begin =
1700b57cec5SDimitry Andric (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
1710b57cec5SDimitry Andric auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1720b57cec5SDimitry Andric auto Range = CharSourceRange::getCharRange(Begin, End);
1730b57cec5SDimitry Andric auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
1740b57cec5SDimitry Andric if (Err) {
1750b57cec5SDimitry Andric llvm::errs() << "Error while sorting using declarations: "
1760b57cec5SDimitry Andric << llvm::toString(std::move(Err)) << "\n";
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric continue;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
1810b57cec5SDimitry Andric continue;
1820b57cec5SDimitry Andric auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
1830b57cec5SDimitry Andric auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1840b57cec5SDimitry Andric auto SortedBegin =
1850b57cec5SDimitry Andric SortedUsingDeclarations[I].Line->First->Tok.getLocation();
1860b57cec5SDimitry Andric auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
1870b57cec5SDimitry Andric StringRef Text(SourceMgr.getCharacterData(SortedBegin),
1880b57cec5SDimitry Andric SourceMgr.getCharacterData(SortedEnd) -
1890b57cec5SDimitry Andric SourceMgr.getCharacterData(SortedBegin));
1900b57cec5SDimitry Andric LLVM_DEBUG({
1910b57cec5SDimitry Andric StringRef OldText(SourceMgr.getCharacterData(Begin),
1920b57cec5SDimitry Andric SourceMgr.getCharacterData(End) -
1930b57cec5SDimitry Andric SourceMgr.getCharacterData(Begin));
1940b57cec5SDimitry Andric llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
1950b57cec5SDimitry Andric });
1960b57cec5SDimitry Andric auto Range = CharSourceRange::getCharRange(Begin, End);
1970b57cec5SDimitry Andric auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
1980b57cec5SDimitry Andric if (Err) {
1990b57cec5SDimitry Andric llvm::errs() << "Error while sorting using declarations: "
2000b57cec5SDimitry Andric << llvm::toString(std::move(Err)) << "\n";
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric UsingDeclarations->clear();
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric } // namespace
2070b57cec5SDimitry Andric
UsingDeclarationsSorter(const Environment & Env,const FormatStyle & Style)2080b57cec5SDimitry Andric UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
2090b57cec5SDimitry Andric const FormatStyle &Style)
2100b57cec5SDimitry Andric : TokenAnalyzer(Env, Style) {}
2110b57cec5SDimitry Andric
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)2120b57cec5SDimitry Andric std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
2130b57cec5SDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2140b57cec5SDimitry Andric FormatTokenLexer &Tokens) {
2150b57cec5SDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager();
2160b57cec5SDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
2170b57cec5SDimitry Andric tooling::Replacements Fixes;
2180b57cec5SDimitry Andric SmallVector<UsingDeclaration, 4> UsingDeclarations;
2191fd87a68SDimitry Andric for (const AnnotatedLine *Line : AnnotatedLines) {
2201fd87a68SDimitry Andric const auto *FirstTok = Line->First;
2211fd87a68SDimitry Andric if (Line->InPPDirective || !Line->startsWith(tok::kw_using) ||
2221fd87a68SDimitry Andric FirstTok->Finalized) {
223*bdd1243dSDimitry Andric endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
224*bdd1243dSDimitry Andric Style.SortUsingDeclarations);
2250b57cec5SDimitry Andric continue;
2260b57cec5SDimitry Andric }
227*bdd1243dSDimitry Andric if (FirstTok->NewlinesBefore > 1) {
228*bdd1243dSDimitry Andric endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
229*bdd1243dSDimitry Andric Style.SortUsingDeclarations);
230*bdd1243dSDimitry Andric }
2310b57cec5SDimitry Andric const auto *UsingTok =
2320b57cec5SDimitry Andric FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
2330b57cec5SDimitry Andric std::string Label = computeUsingDeclarationLabel(UsingTok);
2340b57cec5SDimitry Andric if (Label.empty()) {
235*bdd1243dSDimitry Andric endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
236*bdd1243dSDimitry Andric Style.SortUsingDeclarations);
2370b57cec5SDimitry Andric continue;
2380b57cec5SDimitry Andric }
2391fd87a68SDimitry Andric UsingDeclarations.push_back(UsingDeclaration(Line, Label));
2400b57cec5SDimitry Andric }
241*bdd1243dSDimitry Andric endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
242*bdd1243dSDimitry Andric Style.SortUsingDeclarations);
2430b57cec5SDimitry Andric return {Fixes, 0};
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric } // namespace format
2470b57cec5SDimitry Andric } // namespace clang
248